1 // Copyright (C) 2019 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.android.icing; 16 17 import com.google.android.icing.proto.BatchGetResultProto; 18 import com.google.android.icing.proto.BatchPutResultProto; 19 import com.google.android.icing.proto.BlobProto; 20 import com.google.android.icing.proto.DebugInfoResultProto; 21 import com.google.android.icing.proto.DebugInfoVerbosity; 22 import com.google.android.icing.proto.DeleteByNamespaceResultProto; 23 import com.google.android.icing.proto.DeleteByQueryResultProto; 24 import com.google.android.icing.proto.DeleteBySchemaTypeResultProto; 25 import com.google.android.icing.proto.DeleteResultProto; 26 import com.google.android.icing.proto.DocumentProto; 27 import com.google.android.icing.proto.GetAllNamespacesResultProto; 28 import com.google.android.icing.proto.GetOptimizeInfoResultProto; 29 import com.google.android.icing.proto.GetResultProto; 30 import com.google.android.icing.proto.GetResultSpecProto; 31 import com.google.android.icing.proto.GetSchemaResultProto; 32 import com.google.android.icing.proto.GetSchemaTypeResultProto; 33 import com.google.android.icing.proto.IcingSearchEngineOptions; 34 import com.google.android.icing.proto.InitializeResultProto; 35 import com.google.android.icing.proto.LogSeverity; 36 import com.google.android.icing.proto.OptimizeResultProto; 37 import com.google.android.icing.proto.PersistToDiskResultProto; 38 import com.google.android.icing.proto.PersistType; 39 import com.google.android.icing.proto.PropertyProto; 40 import com.google.android.icing.proto.PutDocumentRequest; 41 import com.google.android.icing.proto.PutResultProto; 42 import com.google.android.icing.proto.ReportUsageResultProto; 43 import com.google.android.icing.proto.ResetResultProto; 44 import com.google.android.icing.proto.ResultSpecProto; 45 import com.google.android.icing.proto.SchemaProto; 46 import com.google.android.icing.proto.ScoringSpecProto; 47 import com.google.android.icing.proto.SearchResultProto; 48 import com.google.android.icing.proto.SearchSpecProto; 49 import com.google.android.icing.proto.SetSchemaRequestProto; 50 import com.google.android.icing.proto.SetSchemaResultProto; 51 import com.google.android.icing.proto.StorageInfoResultProto; 52 import com.google.android.icing.proto.SuggestionResponse; 53 import com.google.android.icing.proto.SuggestionSpecProto; 54 import com.google.android.icing.proto.UsageReport; 55 import org.jspecify.annotations.NonNull; 56 import org.jspecify.annotations.Nullable; 57 58 /** 59 * Java wrapper to access {@link IcingSearchEngineImpl}. 60 * 61 * <p>It converts byte array from {@link IcingSearchEngineImpl} to corresponding protos. 62 * 63 * <p>If this instance has been closed, the instance is no longer usable. 64 * 65 * <p>Keep this class to be non-Final so that it can be mocked in AppSearch. 66 * 67 * <p>NOTE: This class is NOT thread-safe. 68 */ 69 public class IcingSearchEngine implements IcingSearchEngineInterface { 70 71 private static final String TAG = "IcingSearchEngine"; 72 private final IcingSearchEngineImpl icingSearchEngineImpl; 73 74 /** 75 * @throws IllegalStateException if IcingSearchEngine fails to be created 76 */ IcingSearchEngine(@onNull IcingSearchEngineOptions options)77 public IcingSearchEngine(@NonNull IcingSearchEngineOptions options) { 78 icingSearchEngineImpl = new IcingSearchEngineImpl(options.toByteArray()); 79 } 80 81 @Override close()82 public void close() { 83 icingSearchEngineImpl.close(); 84 } 85 86 @Override initialize()87 public @NonNull InitializeResultProto initialize() { 88 return IcingSearchEngineUtils.byteArrayToInitializeResultProto( 89 icingSearchEngineImpl.initialize()); 90 } 91 92 @Override setSchema(@onNull SchemaProto schema)93 public @NonNull SetSchemaResultProto setSchema(@NonNull SchemaProto schema) { 94 return setSchema(schema, /* ignoreErrorsAndDeleteDocuments= */ false); 95 } 96 97 @Override setSchema( @onNull SchemaProto schema, boolean ignoreErrorsAndDeleteDocuments)98 public @NonNull SetSchemaResultProto setSchema( 99 @NonNull SchemaProto schema, boolean ignoreErrorsAndDeleteDocuments) { 100 return IcingSearchEngineUtils.byteArrayToSetSchemaResultProto( 101 icingSearchEngineImpl.setSchema(schema.toByteArray(), ignoreErrorsAndDeleteDocuments)); 102 } 103 104 @Override setSchemaWithRequestProto( @onNull SetSchemaRequestProto setSchemaRequest)105 public @NonNull SetSchemaResultProto setSchemaWithRequestProto( 106 @NonNull SetSchemaRequestProto setSchemaRequest) { 107 return IcingSearchEngineUtils.byteArrayToSetSchemaResultProto( 108 icingSearchEngineImpl.setSchemaWithRequestProto(setSchemaRequest.toByteArray())); 109 } 110 111 @Override getSchema()112 public @NonNull GetSchemaResultProto getSchema() { 113 return IcingSearchEngineUtils.byteArrayToGetSchemaResultProto( 114 icingSearchEngineImpl.getSchema()); 115 } 116 117 @Override getSchemaForDatabase(@onNull String database)118 public @NonNull GetSchemaResultProto getSchemaForDatabase(@NonNull String database) { 119 return IcingSearchEngineUtils.byteArrayToGetSchemaResultProto( 120 icingSearchEngineImpl.getSchemaForDatabase(database)); 121 } 122 123 @Override getSchemaType(@onNull String schemaType)124 public @NonNull GetSchemaTypeResultProto getSchemaType(@NonNull String schemaType) { 125 return IcingSearchEngineUtils.byteArrayToGetSchemaTypeResultProto( 126 icingSearchEngineImpl.getSchemaType(schemaType)); 127 } 128 129 // TODO(b/394875109) We can remove this after we make the change in AppSearch, or keep it and make 130 // it call the batch version. 131 @Override put(@onNull DocumentProto document)132 public @NonNull PutResultProto put(@NonNull DocumentProto document) { 133 return IcingSearchEngineUtils.byteArrayToPutResultProto( 134 icingSearchEngineImpl.put(document.toByteArray())); 135 } 136 137 @Override batchPut(@onNull PutDocumentRequest documents)138 public @NonNull BatchPutResultProto batchPut(@NonNull PutDocumentRequest documents) { 139 return IcingSearchEngineUtils.byteArrayToBatchPutResultProto( 140 icingSearchEngineImpl.batchPut(documents.toByteArray())); 141 } 142 143 @Override get( @onNull String namespace, @NonNull String uri, @NonNull GetResultSpecProto getResultSpec)144 public @NonNull GetResultProto get( 145 @NonNull String namespace, @NonNull String uri, @NonNull GetResultSpecProto getResultSpec) { 146 return IcingSearchEngineUtils.byteArrayToGetResultProto( 147 icingSearchEngineImpl.get(namespace, uri, getResultSpec.toByteArray())); 148 } 149 150 @Override batchGet(@onNull GetResultSpecProto getResultSpec)151 public @NonNull BatchGetResultProto batchGet(@NonNull GetResultSpecProto getResultSpec) { 152 return IcingSearchEngineUtils.byteArrayToBatchGetResultProto( 153 icingSearchEngineImpl.batchGet(getResultSpec.toByteArray())); 154 } 155 156 @Override reportUsage(@onNull UsageReport usageReport)157 public @NonNull ReportUsageResultProto reportUsage(@NonNull UsageReport usageReport) { 158 return IcingSearchEngineUtils.byteArrayToReportUsageResultProto( 159 icingSearchEngineImpl.reportUsage(usageReport.toByteArray())); 160 } 161 162 @Override getAllNamespaces()163 public @NonNull GetAllNamespacesResultProto getAllNamespaces() { 164 return IcingSearchEngineUtils.byteArrayToGetAllNamespacesResultProto( 165 icingSearchEngineImpl.getAllNamespaces()); 166 } 167 168 @Override search( @onNull SearchSpecProto searchSpec, @NonNull ScoringSpecProto scoringSpec, @NonNull ResultSpecProto resultSpec)169 public @NonNull SearchResultProto search( 170 @NonNull SearchSpecProto searchSpec, 171 @NonNull ScoringSpecProto scoringSpec, 172 @NonNull ResultSpecProto resultSpec) { 173 return IcingSearchEngineUtils.byteArrayToSearchResultProto( 174 icingSearchEngineImpl.search( 175 searchSpec.toByteArray(), scoringSpec.toByteArray(), resultSpec.toByteArray())); 176 } 177 178 @Override getNextPage(long nextPageToken)179 public @NonNull SearchResultProto getNextPage(long nextPageToken) { 180 return IcingSearchEngineUtils.byteArrayToSearchResultProto( 181 icingSearchEngineImpl.getNextPage(nextPageToken)); 182 } 183 184 @Override invalidateNextPageToken(long nextPageToken)185 public void invalidateNextPageToken(long nextPageToken) { 186 icingSearchEngineImpl.invalidateNextPageToken(nextPageToken); 187 } 188 189 @Override openWriteBlob(PropertyProto.@onNull BlobHandleProto blobHandle)190 public @NonNull BlobProto openWriteBlob(PropertyProto.@NonNull BlobHandleProto blobHandle) { 191 return IcingSearchEngineUtils.byteArrayToBlobProto( 192 icingSearchEngineImpl.openWriteBlob(blobHandle.toByteArray())); 193 } 194 195 @Override removeBlob(PropertyProto.@onNull BlobHandleProto blobHandle)196 public @NonNull BlobProto removeBlob(PropertyProto.@NonNull BlobHandleProto blobHandle) { 197 return IcingSearchEngineUtils.byteArrayToBlobProto( 198 icingSearchEngineImpl.removeBlob(blobHandle.toByteArray())); 199 } 200 201 @Override openReadBlob(PropertyProto.@onNull BlobHandleProto blobHandle)202 public @NonNull BlobProto openReadBlob(PropertyProto.@NonNull BlobHandleProto blobHandle) { 203 return IcingSearchEngineUtils.byteArrayToBlobProto( 204 icingSearchEngineImpl.openReadBlob(blobHandle.toByteArray())); 205 } 206 207 @Override commitBlob(PropertyProto.@onNull BlobHandleProto blobHandle)208 public @NonNull BlobProto commitBlob(PropertyProto.@NonNull BlobHandleProto blobHandle) { 209 return IcingSearchEngineUtils.byteArrayToBlobProto( 210 icingSearchEngineImpl.commitBlob(blobHandle.toByteArray())); 211 } 212 213 @Override delete(@onNull String namespace, @NonNull String uri)214 public @NonNull DeleteResultProto delete(@NonNull String namespace, @NonNull String uri) { 215 return IcingSearchEngineUtils.byteArrayToDeleteResultProto( 216 icingSearchEngineImpl.delete(namespace, uri)); 217 } 218 219 @Override searchSuggestions( @onNull SuggestionSpecProto suggestionSpec)220 public @NonNull SuggestionResponse searchSuggestions( 221 @NonNull SuggestionSpecProto suggestionSpec) { 222 return IcingSearchEngineUtils.byteArrayToSuggestionResponse( 223 icingSearchEngineImpl.searchSuggestions(suggestionSpec.toByteArray())); 224 } 225 226 @Override deleteByNamespace(@onNull String namespace)227 public @NonNull DeleteByNamespaceResultProto deleteByNamespace(@NonNull String namespace) { 228 return IcingSearchEngineUtils.byteArrayToDeleteByNamespaceResultProto( 229 icingSearchEngineImpl.deleteByNamespace(namespace)); 230 } 231 232 @Override deleteBySchemaType(@onNull String schemaType)233 public @NonNull DeleteBySchemaTypeResultProto deleteBySchemaType(@NonNull String schemaType) { 234 return IcingSearchEngineUtils.byteArrayToDeleteBySchemaTypeResultProto( 235 icingSearchEngineImpl.deleteBySchemaType(schemaType)); 236 } 237 238 @Override deleteByQuery(@onNull SearchSpecProto searchSpec)239 public @NonNull DeleteByQueryResultProto deleteByQuery(@NonNull SearchSpecProto searchSpec) { 240 return deleteByQuery(searchSpec, /* returnDeletedDocumentInfo= */ false); 241 } 242 243 @Override deleteByQuery( @onNull SearchSpecProto searchSpec, boolean returnDeletedDocumentInfo)244 public @NonNull DeleteByQueryResultProto deleteByQuery( 245 @NonNull SearchSpecProto searchSpec, boolean returnDeletedDocumentInfo) { 246 return IcingSearchEngineUtils.byteArrayToDeleteByQueryResultProto( 247 icingSearchEngineImpl.deleteByQuery(searchSpec.toByteArray(), returnDeletedDocumentInfo)); 248 } 249 250 @Override persistToDisk( PersistType.@onNull Code persistTypeCode)251 public @NonNull PersistToDiskResultProto persistToDisk( 252 PersistType.@NonNull Code persistTypeCode) { 253 return IcingSearchEngineUtils.byteArrayToPersistToDiskResultProto( 254 icingSearchEngineImpl.persistToDisk(persistTypeCode.getNumber())); 255 } 256 257 @Override optimize()258 public @NonNull OptimizeResultProto optimize() { 259 return IcingSearchEngineUtils.byteArrayToOptimizeResultProto(icingSearchEngineImpl.optimize()); 260 } 261 262 @Override getOptimizeInfo()263 public @NonNull GetOptimizeInfoResultProto getOptimizeInfo() { 264 return IcingSearchEngineUtils.byteArrayToGetOptimizeInfoResultProto( 265 icingSearchEngineImpl.getOptimizeInfo()); 266 } 267 268 @Override getStorageInfo()269 public @NonNull StorageInfoResultProto getStorageInfo() { 270 return IcingSearchEngineUtils.byteArrayToStorageInfoResultProto( 271 icingSearchEngineImpl.getStorageInfo()); 272 } 273 274 @Override getDebugInfo(DebugInfoVerbosity.@onNull Code verbosity)275 public @NonNull DebugInfoResultProto getDebugInfo(DebugInfoVerbosity.@NonNull Code verbosity) { 276 return IcingSearchEngineUtils.byteArrayToDebugInfoResultProto( 277 icingSearchEngineImpl.getDebugInfo(verbosity.getNumber())); 278 } 279 280 @Override reset()281 public @NonNull ResetResultProto reset() { 282 return IcingSearchEngineUtils.byteArrayToResetResultProto(icingSearchEngineImpl.reset()); 283 } 284 shouldLog(LogSeverity.Code severity)285 public static boolean shouldLog(LogSeverity.Code severity) { 286 return shouldLog(severity, (short) 0); 287 } 288 shouldLog(LogSeverity.Code severity, short verbosity)289 public static boolean shouldLog(LogSeverity.Code severity, short verbosity) { 290 return IcingSearchEngineImpl.shouldLog((short) severity.getNumber(), verbosity); 291 } 292 setLoggingLevel(LogSeverity.Code severity)293 public static boolean setLoggingLevel(LogSeverity.Code severity) { 294 return setLoggingLevel(severity, (short) 0); 295 } 296 setLoggingLevel(LogSeverity.Code severity, short verbosity)297 public static boolean setLoggingLevel(LogSeverity.Code severity, short verbosity) { 298 return IcingSearchEngineImpl.setLoggingLevel((short) severity.getNumber(), verbosity); 299 } 300 getLoggingTag()301 public static @Nullable String getLoggingTag() { 302 return IcingSearchEngineImpl.getLoggingTag(); 303 } 304 } 305