1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.appsearch.localstorage; 18 19 import androidx.annotation.RestrictTo; 20 import androidx.annotation.VisibleForTesting; 21 import androidx.appsearch.localstorage.util.PrefixUtil; 22 import androidx.collection.ArrayMap; 23 import androidx.collection.ArraySet; 24 25 import org.jspecify.annotations.NonNull; 26 import org.jspecify.annotations.Nullable; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Map; 31 import java.util.Set; 32 33 /** 34 * Caches and manages namespace information for AppSearch. 35 * 36 * This class is NOT thread safety. 37 * 38 * @exportToFramework:hide 39 */ 40 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 41 public class NamespaceCache { 42 43 // This map contains namespaces for all package-database prefixes. All values in the map are 44 // prefixed with the package-database prefix. 45 private final Map<String, Set<String>> mDocumentNamespaceMap = new ArrayMap<>(); 46 47 // This map contains blob namespaces for all package-database prefixes. All values in the map 48 // are prefixed with the package-database prefix. 49 private final Map<String, Set<String>> mBlobNamespaceMap = new ArrayMap<>(); 50 NamespaceCache()51 public NamespaceCache() {} 52 53 @VisibleForTesting NamespaceCache(@onNull Map<String, Set<String>> documentNamespaceMap)54 public NamespaceCache(@NonNull Map<String, Set<String>> documentNamespaceMap) { 55 mDocumentNamespaceMap.putAll(documentNamespaceMap); 56 } 57 58 /** Gets all prefixed document namespaces of the given set of packages. */ getAllPrefixedDocumentNamespaceForPackages( @onNull Set<String> packageNames)59 public @NonNull Set<String> getAllPrefixedDocumentNamespaceForPackages( 60 @NonNull Set<String> packageNames) { 61 Set<String> wantedPrefixedNamespaces = new ArraySet<>(); 62 63 // Accumulate all the namespaces we're interested in. 64 for (Map.Entry<String, Set<String>> entry : mDocumentNamespaceMap.entrySet()) { 65 if (packageNames.contains(PrefixUtil.getPackageName(entry.getKey()))) { 66 wantedPrefixedNamespaces.addAll(entry.getValue()); 67 } 68 } 69 return wantedPrefixedNamespaces; 70 } 71 72 /** Gets all prefixed document blob namespaces of the given set of packages. */ getAllPrefixedBlobNamespaceForPackages( @onNull Set<String> packageNames)73 public @NonNull Set<String> getAllPrefixedBlobNamespaceForPackages( 74 @NonNull Set<String> packageNames) { 75 Set<String> wantedPrefixedNamespaces = new ArraySet<>(); 76 77 // Accumulate all the namespaces we're interested in. 78 for (Map.Entry<String, Set<String>> entry : mBlobNamespaceMap.entrySet()) { 79 if (packageNames.contains(PrefixUtil.getPackageName(entry.getKey()))) { 80 wantedPrefixedNamespaces.addAll(entry.getValue()); 81 } 82 } 83 return wantedPrefixedNamespaces; 84 } 85 86 /** Gets prefixed document namespaces of the given prefix. */ getPrefixedDocumentNamespaces(@onNull String prefix)87 public @Nullable Set<String> getPrefixedDocumentNamespaces(@NonNull String prefix) { 88 return mDocumentNamespaceMap.get(prefix); 89 } 90 91 /** Gets prefixed blob namespaces of the given prefix. */ getPrefixedBlobNamespaces(@onNull String prefix)92 public @Nullable Set<String> getPrefixedBlobNamespaces(@NonNull String prefix) { 93 return mBlobNamespaceMap.get(prefix); 94 } 95 96 /** Gets all prefixes that contains documents in AppSearch. */ getAllDocumentPrefixes()97 public @NonNull Set<String> getAllDocumentPrefixes() { 98 return mDocumentNamespaceMap.keySet(); 99 } 100 101 102 /** Gets all prefixed blob namespaces in AppSearch. */ getAllPrefixedBlobNamespaces()103 public @NonNull List<String> getAllPrefixedBlobNamespaces() { 104 List<String> prefixedBlobNamespaces = new ArrayList<>(); 105 for (Set<String> value : mBlobNamespaceMap.values()) { 106 prefixedBlobNamespaces.addAll(value); 107 } 108 return prefixedBlobNamespaces; 109 } 110 111 /** Removes prefixed document namespaces under the given prefix. */ removeDocumentNamespaces(@onNull String prefix)112 public @Nullable Set<String> removeDocumentNamespaces(@NonNull String prefix) { 113 return mDocumentNamespaceMap.remove(prefix); 114 } 115 116 /** Add the given prefixed namespace to document namespace map. */ addToDocumentNamespaceMap(@onNull String prefix, @NonNull String prefixedNamespace)117 public void addToDocumentNamespaceMap(@NonNull String prefix, 118 @NonNull String prefixedNamespace) { 119 addToMap(mDocumentNamespaceMap, prefix, prefixedNamespace); 120 } 121 122 /** Add the given prefixed namespace to blob namespace map. */ addToBlobNamespaceMap(@onNull String prefix, @NonNull String prefixedNamespace)123 public void addToBlobNamespaceMap(@NonNull String prefix, @NonNull String prefixedNamespace) { 124 addToMap(mBlobNamespaceMap, prefix, prefixedNamespace); 125 } 126 127 /** 128 * Clears all data in the cache. 129 */ clear()130 public void clear() { 131 mDocumentNamespaceMap.clear(); 132 mBlobNamespaceMap.clear(); 133 } 134 addToMap(Map<String, Set<String>> map, String prefix, String prefixedValue)135 private static void addToMap(Map<String, Set<String>> map, String prefix, 136 String prefixedValue) { 137 Set<String> values = map.get(prefix); 138 if (values == null) { 139 values = new ArraySet<>(); 140 map.put(prefix, values); 141 } 142 values.add(prefixedValue); 143 } 144 } 145