1 /* 2 * Copyright 2020 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 package android.app.appsearch; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.util.ArrayMap; 21 22 import java.util.Collections; 23 import java.util.Map; 24 import java.util.Objects; 25 26 /** 27 * Provides results for AppSearch batch operations which encompass multiple documents. 28 * 29 * <p>Individual results of a batch operation are separated into two maps: one for successes and one 30 * for failures. For successes, {@link #getSuccesses()} will return a map of keys to instances of 31 * the value type. For failures, {@link #getFailures()} will return a map of keys to {@link 32 * AppSearchResult} objects. 33 * 34 * <p>Alternatively, {@link #getAll()} returns a map of keys to {@link AppSearchResult} objects for 35 * both successes and failures. 36 * 37 * @param <KeyType> The type of the keys for which the results will be reported. 38 * @param <ValueType> The type of the result objects for successful results. 39 * @see AppSearchSession#put 40 * @see AppSearchSession#getByDocumentId 41 * @see AppSearchSession#remove 42 */ 43 public final class AppSearchBatchResult<KeyType, ValueType> { 44 @NonNull private final Map<KeyType, ValueType> mSuccesses; 45 @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures; 46 @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mAll; 47 AppSearchBatchResult( @onNull Map<KeyType, ValueType> successes, @NonNull Map<KeyType, AppSearchResult<ValueType>> failures, @NonNull Map<KeyType, AppSearchResult<ValueType>> all)48 AppSearchBatchResult( 49 @NonNull Map<KeyType, ValueType> successes, 50 @NonNull Map<KeyType, AppSearchResult<ValueType>> failures, 51 @NonNull Map<KeyType, AppSearchResult<ValueType>> all) { 52 mSuccesses = Objects.requireNonNull(successes); 53 mFailures = Objects.requireNonNull(failures); 54 mAll = Objects.requireNonNull(all); 55 } 56 57 /** Returns {@code true} if this {@link AppSearchBatchResult} has no failures. */ isSuccess()58 public boolean isSuccess() { 59 return mFailures.isEmpty(); 60 } 61 62 /** 63 * Returns a {@link Map} of keys mapped to instances of the value type for all successful 64 * individual results. 65 * 66 * <p>Example: {@link AppSearchSession#getByDocumentId} returns an {@link AppSearchBatchResult}. 67 * Each key (the document ID, of {@code String} type) will map to a {@link GenericDocument} 68 * object. 69 * 70 * <p>The values of the {@link Map} will not be {@code null}. 71 */ 72 @NonNull getSuccesses()73 public Map<KeyType, ValueType> getSuccesses() { 74 return Collections.unmodifiableMap(mSuccesses); 75 } 76 77 /** 78 * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all failed 79 * individual results. 80 * 81 * <p>The values of the {@link Map} will not be {@code null}. 82 */ 83 @NonNull getFailures()84 public Map<KeyType, AppSearchResult<ValueType>> getFailures() { 85 return Collections.unmodifiableMap(mFailures); 86 } 87 88 /** 89 * Returns a {@link Map} of keys mapped to instances of {@link AppSearchResult} for all 90 * individual results. 91 * 92 * <p>The values of the {@link Map} will not be {@code null}. 93 */ 94 @NonNull getAll()95 public Map<KeyType, AppSearchResult<ValueType>> getAll() { 96 return Collections.unmodifiableMap(mAll); 97 } 98 99 /** 100 * Asserts that this {@link AppSearchBatchResult} has no failures. 101 * 102 * @hide 103 */ checkSuccess()104 public void checkSuccess() { 105 if (!isSuccess()) { 106 throw new IllegalStateException("AppSearchBatchResult has failures: " + this); 107 } 108 } 109 110 @Override 111 @NonNull toString()112 public String toString() { 113 return "{\n successes: " + mSuccesses + "\n failures: " + mFailures + "\n}"; 114 } 115 116 /** 117 * Builder for {@link AppSearchBatchResult} objects. 118 * 119 * @param <KeyType> The type of the keys for which the results will be reported. 120 * @param <ValueType> The type of the result objects for successful results. 121 */ 122 public static final class Builder<KeyType, ValueType> { 123 private ArrayMap<KeyType, ValueType> mSuccesses = new ArrayMap<>(); 124 private ArrayMap<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>(); 125 private ArrayMap<KeyType, AppSearchResult<ValueType>> mAll = new ArrayMap<>(); 126 private boolean mBuilt = false; 127 128 /** 129 * Associates the {@code key} with the provided successful return value. 130 * 131 * <p>Any previous mapping for a key, whether success or failure, is deleted. 132 * 133 * <p>This is a convenience function which is equivalent to {@code setResult(key, 134 * AppSearchResult.newSuccessfulResult(value))}. 135 * 136 * @param key The key to associate the result with; usually corresponds to some identifier 137 * from the input like an ID or name. 138 * @param value An optional value to associate with the successful result of the operation 139 * being performed. 140 */ 141 @SuppressWarnings("MissingGetterMatchingBuilder") // See getSuccesses 142 @NonNull setSuccess( @onNull KeyType key, @Nullable ValueType value)143 public Builder<KeyType, ValueType> setSuccess( 144 @NonNull KeyType key, @Nullable ValueType value) { 145 Objects.requireNonNull(key); 146 resetIfBuilt(); 147 return setResult(key, AppSearchResult.newSuccessfulResult(value)); 148 } 149 150 /** 151 * Associates the {@code key} with the provided failure code and error message. 152 * 153 * <p>Any previous mapping for a key, whether success or failure, is deleted. 154 * 155 * <p>This is a convenience function which is equivalent to {@code setResult(key, 156 * AppSearchResult.newFailedResult(resultCode, errorMessage))}. 157 * 158 * @param key The key to associate the result with; usually corresponds to some identifier 159 * from the input like an ID or name. 160 * @param resultCode One of the constants documented in {@link 161 * AppSearchResult#getResultCode}. 162 * @param errorMessage An optional string describing the reason or nature of the failure. 163 */ 164 @SuppressWarnings("MissingGetterMatchingBuilder") // See getFailures 165 @NonNull setFailure( @onNull KeyType key, @AppSearchResult.ResultCode int resultCode, @Nullable String errorMessage)166 public Builder<KeyType, ValueType> setFailure( 167 @NonNull KeyType key, 168 @AppSearchResult.ResultCode int resultCode, 169 @Nullable String errorMessage) { 170 Objects.requireNonNull(key); 171 resetIfBuilt(); 172 return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage)); 173 } 174 175 /** 176 * Associates the {@code key} with the provided {@code result}. 177 * 178 * <p>Any previous mapping for a key, whether success or failure, is deleted. 179 * 180 * @param key The key to associate the result with; usually corresponds to some identifier 181 * from the input like an ID or name. 182 * @param result The result to associate with the key. 183 */ 184 @SuppressWarnings("MissingGetterMatchingBuilder") // See getAll 185 @NonNull setResult( @onNull KeyType key, @NonNull AppSearchResult<ValueType> result)186 public Builder<KeyType, ValueType> setResult( 187 @NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) { 188 Objects.requireNonNull(key); 189 Objects.requireNonNull(result); 190 resetIfBuilt(); 191 if (result.isSuccess()) { 192 mSuccesses.put(key, result.getResultValue()); 193 mFailures.remove(key); 194 } else { 195 mFailures.put(key, result); 196 mSuccesses.remove(key); 197 } 198 mAll.put(key, result); 199 return this; 200 } 201 202 /** 203 * Builds an {@link AppSearchBatchResult} object from the contents of this {@link Builder}. 204 */ 205 @NonNull build()206 public AppSearchBatchResult<KeyType, ValueType> build() { 207 mBuilt = true; 208 return new AppSearchBatchResult<>(mSuccesses, mFailures, mAll); 209 } 210 resetIfBuilt()211 private void resetIfBuilt() { 212 if (mBuilt) { 213 mSuccesses = new ArrayMap<>(mSuccesses); 214 mFailures = new ArrayMap<>(mFailures); 215 mAll = new ArrayMap<>(mAll); 216 mBuilt = false; 217 } 218 } 219 } 220 } 221