blob: a12352bd252bd6ff3bd77c9379be951b88c5ea7f [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.icing;
import android.annotation.NonNull;
import android.util.Log;
import com.google.android.icing.proto.DeleteByNamespaceResultProto;
import com.google.android.icing.proto.DeleteBySchemaTypeResultProto;
import com.google.android.icing.proto.DeleteResultProto;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.GetResultProto;
import com.google.android.icing.proto.GetSchemaResultProto;
import com.google.android.icing.proto.GetSchemaTypeResultProto;
import com.google.android.icing.proto.IcingSearchEngineOptions;
import com.google.android.icing.proto.InitializeResultProto;
import com.google.android.icing.proto.OptimizeResultProto;
import com.google.android.icing.proto.PersistToDiskResultProto;
import com.google.android.icing.proto.PutResultProto;
import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.SchemaProto;
import com.google.android.icing.proto.ScoringSpecProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.SetSchemaResultProto;
import com.google.android.icing.proto.StatusProto;
import com.google.protobuf.InvalidProtocolBufferException;
/** Java wrapper to access native APIs in external/icing/icing/icing-search-engine.h */
public final class IcingSearchEngine {
private static final String TAG = "IcingSearchEngine";
private long mNativePointer;
static {
// NOTE: This can fail with an UnsatisfiedLinkError
System.loadLibrary("icing_jni");
}
/**
* @throws RuntimeException if IcingSearchEngine fails to be created
*/
public IcingSearchEngine(IcingSearchEngineOptions options) {
mNativePointer = nativeCreate(options.toByteArray());
if (mNativePointer == 0) {
Log.e(TAG, "Failed to create IcingSearchEngine.");
throw new RuntimeException("Failed to create IcingSearchEngine.");
}
}
@NonNull
public InitializeResultProto initialize() {
byte[] initializeResultBytes = nativeInitialize(mNativePointer);
if (initializeResultBytes == null) {
Log.e(TAG, "Received null InitializeResult from native.");
return InitializeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return InitializeResultProto.parseFrom(initializeResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing InitializeResultProto.", e);
return InitializeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public SetSchemaResultProto setSchema(@NonNull SchemaProto schema) {
return setSchema(schema, /*ignoreErrorsAndDeleteDocuments=*/ false);
}
@NonNull
public SetSchemaResultProto setSchema(
@NonNull SchemaProto schema, boolean ignoreErrorsAndDeleteDocuments) {
byte[] setSchemaResultBytes =
nativeSetSchema(mNativePointer, schema.toByteArray(), ignoreErrorsAndDeleteDocuments);
if (setSchemaResultBytes == null) {
Log.e(TAG, "Received null SetSchemaResultProto from native.");
return SetSchemaResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return SetSchemaResultProto.parseFrom(setSchemaResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing SetSchemaResultProto.", e);
return SetSchemaResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public GetSchemaResultProto getSchema() {
byte[] getSchemaResultBytes = nativeGetSchema(mNativePointer);
if (getSchemaResultBytes == null) {
Log.e(TAG, "Received null GetSchemaResultProto from native.");
return GetSchemaResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return GetSchemaResultProto.parseFrom(getSchemaResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing GetSchemaResultProto.", e);
return GetSchemaResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public GetSchemaTypeResultProto getSchemaType(@NonNull String schemaType) {
byte[] getSchemaTypeResultBytes = nativeGetSchemaType(mNativePointer, schemaType);
if (getSchemaTypeResultBytes == null) {
Log.e(TAG, "Received null GetSchemaTypeResultProto from native.");
return GetSchemaTypeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return GetSchemaTypeResultProto.parseFrom(getSchemaTypeResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing GetSchemaTypeResultProto.", e);
return GetSchemaTypeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public PutResultProto put(@NonNull DocumentProto document) {
byte[] putResultBytes = nativePut(mNativePointer, document.toByteArray());
if (putResultBytes == null) {
Log.e(TAG, "Received null PutResultProto from native.");
return PutResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return PutResultProto.parseFrom(putResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing PutResultProto.", e);
return PutResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public GetResultProto get(@NonNull String namespace, @NonNull String uri) {
byte[] getResultBytes = nativeGet(mNativePointer, namespace, uri);
if (getResultBytes == null) {
Log.e(TAG, "Received null GetResultProto from native.");
return GetResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return GetResultProto.parseFrom(getResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing GetResultProto.", e);
return GetResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public SearchResultProto search(
@NonNull SearchSpecProto searchSpec, @NonNull ScoringSpecProto scoringSpec, @NonNull ResultSpecProto resultSpec) {
byte[] searchResultBytes =
nativeSearch(
mNativePointer,
searchSpec.toByteArray(),
scoringSpec.toByteArray(),
resultSpec.toByteArray());
if (searchResultBytes == null) {
Log.e(TAG, "Received null SearchResultProto from native.");
return SearchResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return SearchResultProto.parseFrom(searchResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing SearchResultProto.", e);
return SearchResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public DeleteResultProto delete(@NonNull String namespace, @NonNull String uri) {
byte[] deleteResultBytes = nativeDelete(mNativePointer, namespace, uri);
if (deleteResultBytes == null) {
Log.e(TAG, "Received null DeleteResultProto from native.");
return DeleteResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return DeleteResultProto.parseFrom(deleteResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing DeleteResultProto.", e);
return DeleteResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public DeleteByNamespaceResultProto deleteByNamespace(@NonNull String namespace) {
byte[] deleteByNamespaceResultBytes = nativeDeleteByNamespace(mNativePointer, namespace);
if (deleteByNamespaceResultBytes == null) {
Log.e(TAG, "Received null DeleteByNamespaceResultProto from native.");
return DeleteByNamespaceResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return DeleteByNamespaceResultProto.parseFrom(deleteByNamespaceResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing DeleteByNamespaceResultProto.", e);
return DeleteByNamespaceResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public DeleteBySchemaTypeResultProto deleteBySchemaType(@NonNull String schemaType) {
byte[] deleteBySchemaTypeResultBytes = nativeDeleteBySchemaType(mNativePointer, schemaType);
if (deleteBySchemaTypeResultBytes == null) {
Log.e(TAG, "Received null DeleteBySchemaTypeResultProto from native.");
return DeleteBySchemaTypeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return DeleteBySchemaTypeResultProto.parseFrom(deleteBySchemaTypeResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing DeleteBySchemaTypeResultProto.", e);
return DeleteBySchemaTypeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public PersistToDiskResultProto persistToDisk() {
byte[] persistToDiskResultBytes = nativePersistToDisk(mNativePointer);
if (persistToDiskResultBytes == null) {
Log.e(TAG, "Received null PersistToDiskResultProto from native.");
return PersistToDiskResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return PersistToDiskResultProto.parseFrom(persistToDiskResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing PersistToDiskResultProto.", e);
return PersistToDiskResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
@NonNull
public OptimizeResultProto optimize() {
byte[] optimizeResultBytes = nativeOptimize(mNativePointer);
if (optimizeResultBytes == null) {
Log.e(TAG, "Received null OptimizeResultProto from native.");
return OptimizeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
try {
return OptimizeResultProto.parseFrom(optimizeResultBytes);
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Error parsing OptimizeResultProto.", e);
return OptimizeResultProto.newBuilder()
.setStatus(StatusProto.newBuilder().setCode(StatusProto.Code.INTERNAL))
.build();
}
}
private static native long nativeCreate(byte[] icingSearchEngineOptionsBytes);
private static native byte[] nativeInitialize(long mNativePointer);
private static native byte[] nativeSetSchema(
long mNativePointer, byte[] schemaBytes, boolean ignoreErrorsAndDeleteDocuments);
private static native byte[] nativeGetSchema(long mNativePointer);
private static native byte[] nativeGetSchemaType(long mNativePointer, String schemaType);
private static native byte[] nativePut(long mNativePointer, byte[] documentBytes);
private static native byte[] nativeGet(long mNativePointer, String namespace, String uri);
private static native byte[] nativeSearch(
long mNativePointer, byte[] searchSpecBytes, byte[] scoringSpecBytes, byte[] resultSpecBytes);
private static native byte[] nativeDelete(long mNativePointer, String namespace, String uri);
private static native byte[] nativeDeleteByNamespace(long mNativePointer, String namespace);
private static native byte[] nativeDeleteBySchemaType(long mNativePointer, String schemaType);
private static native byte[] nativePersistToDisk(long mNativePointer);
private static native byte[] nativeOptimize(long mNativePointer);
}