// Copyright 2012 Google Inc. All Rights Reserved. // // 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.collide.clientlibs.network.shared; import com.google.collide.client.util.QueryCallback; import com.google.collide.dto.ServerError.FailureReason; import com.google.collide.json.shared.JsonArray; import com.google.collide.json.shared.JsonStringMap; import com.google.collide.shared.util.JsonCollections; import com.google.common.base.Joiner; /** * An object which prevents multiple identical requests from being sent across * the wire to the frontend. When a new requests matches an existing request its * callback is queued. After the initial request returns all callbacks are * notified of success or failure. This object should only be used for requests * which cause no server-side side effects (i.e. creating project). * * @param <R> The type sent to the query callback on success or failure */ public class RequestMerger<R> { /** * Static factory to create a RequestMerger * * @param <R> Type sent to the query callback */ public static <R> RequestMerger<R> create() { return new RequestMerger<R>(); } /** * Convenience constant for merging all requests. */ public static final String ALL_REQUESTS = "ALL"; private JsonStringMap<JsonArray<QueryCallback<R>>> requestMap = JsonCollections.createMap(); /** * Adds a new request to the map, returning true if the exact requestHash is a * currently outstanding request and should not be sent over the wire. * * @param requestHash Unique hash identifying this request's parameters. * @param callback Callback to call on success/failure. * * @return true to indicate that this is a new request, false to indicate that * it is a duplicate of an existing request and has been queued. */ public boolean handleNewRequest(String requestHash, QueryCallback<R> callback) { JsonArray<QueryCallback<R>> callbacks = requestMap.get(requestHash); boolean existed = callbacks != null; if (callbacks == null) { callbacks = JsonCollections.createArray(); requestMap.put(requestHash, callbacks); } callbacks.add(callback); return !existed; } /** * Call to notify all callbacks waiting on a request of failure. */ public void handleQueryFailed(String requestHash, FailureReason reason) { JsonArray<QueryCallback<R>> callbacks = requestMap.remove(requestHash); if (callbacks == null) { return; } for (int i = 0; i < callbacks.size(); i++) { callbacks.get(i).onFail(reason); } } /** * Handles notifying all callbacks waiting on a request of success. */ public void handleQuerySuccess(String requestHash, R result) { JsonArray<QueryCallback<R>> callbacks = requestMap.remove(requestHash); if (callbacks == null) { return; } for (int i = 0; i < callbacks.size(); i++) { callbacks.get(i).onQuerySuccess(result); } } /** * Clears any callbacks waiting on the given request. */ public void clearCallbacksWaitingForRequest(String requestHash) { requestMap.remove(requestHash); } /** * @return the number of callbacks merged and waiting on a given request. */ public boolean hasCallbacksWaitingForRequest(String requestHash) { JsonArray<QueryCallback<R>> callbacks = requestMap.get(requestHash); return callbacks != null && callbacks.size() > 0; } /** * Creates a '|' separated hash string from a list of string values. Calls * {@link Object#toString()} on each value passed in to make the hash. */ public static String createHash(Object... values) { return Joiner.on("|").join(values); } }