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