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