aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android/volley/WaitingRequestManager.java
diff options
context:
space:
mode:
authorAnonymous <no-reply@google.com>2020-10-02 16:21:32 -0700
committerJeff Davidson <jpd@google.com>2020-10-07 01:33:22 +0000
commitb6bd7aa39db62c517d97ff0a97d8d073bdf83a47 (patch)
treeb9b7a6b9928136e83fda62aaa8b8887df88839b5 /src/main/java/com/android/volley/WaitingRequestManager.java
parentdc9062756c4835ac62ade2f3fb8ace20e8dbf3a6 (diff)
downloadvolley-b6bd7aa39db62c517d97ff0a97d8d073bdf83a47.tar.gz
Import of Volley from GitHub to AOSP.
Includes AsyncRequestQueue and asynchronous infrastructure, but the Cronet-based components are excluded from Android.bp as Cronet is not broadly exposed for application usage. - ae701b33e718782e914108f9b6d1f1bb5f1ab7f8 Fix empty responses when content length is unknown. by Jeff Davidson <jpd@google.com> - 055fc535255367e5556d6274aadcbb5cd3be5ed3 Add hook to allow customization of UrlRequest.Builder. by Jeff Davidson <jpd@google.com> - bc64707525d43b2ddc1cad08a3445cc34111c47f Set Content-Type header for requests with bodies. (#371) by Jeff Davidson <jpd@google.com> - 4083c43bcfc8cc31be709574f6d1b923c2bf869d Add cURL logging support to CronetHttpStack. (#370) by Jeff Davidson <jpd@google.com> - 46a4f9040126940be79b10633be470dea32958a3 Fix dependencies from base Volley package to toolbox pack... by Jeff Davidson <jpd@google.com> - cde6d4367210819f357b1397d17b4656b773a0d9 Provide a ScheduledExecutorService to AsyncRequestQueue/A... by Jeff Davidson <jpd@google.com> - f582ee6f7b7067b6bce21239f904f3066b778dad Move CronetHttpStack tests to the expected location. (#368) by Jeff Davidson <jpd@google.com> - a4954c6661b01a5950f973d873b8e21d2a5dcc40 Revert DiskBasedCache. (#366) by Jeff Davidson <jpd@google.com> - 7b0a3119b499989c31611a8fb944015aa9a400c5 AsyncRequestQueue implementation + some tests (#361) by sphill99 <s.phill99@gmail.com> - d777e8a7bc4136b311913178021894adec73bfdb Created builder for DiskBasedAsyncCache (#360) by sphill99 <s.phill99@gmail.com> - 3ff2427da1db5c5a46c1dfa0aaf7c097258be7ce AsyncNetwork implementation as well as unit testing (#357) by sphill99 <s.phill99@gmail.com> - bb85de2f41a1bf9fe8b1ef15a41a9057947a0724 Added licensing headers for all newly created files (#358) by sphill99 <s.phill99@gmail.com> - 82c828d65a8f317a55a1a7b067a60df8fe566a02 AsyncHttpStack and Cronet implementation. Limited unit te... by sphill99 <s.phill99@gmail.com> - d0fb8dea486cc9b164cf140661225160dd5454d7 Implementations for rest of AsyncCache, tests for cache m... by sphill99 <s.phill99@gmail.com> - 94e3a4da70cf1803426de6a2579676966c670d78 Include license in generated POM file. (#352) by Jeff Davidson <jpd@google.com> - cae1570bc5d96cd2b840b39e5c742a397c76b45f Put implementation for async cache that uses callback met... by sphill99 <s.phill99@gmail.com> - a791d09a6747ca4923352405b20c229eafad5866 Get Implementation in AsyncCache that takes in a callback... by sphill99 <s.phill99@gmail.com> - 504e41a1c749ebbf3b63b6ab58533c8219cb6df1 Retry on NoConnectionError (#342) by sphill99 <s.phill99@gmail.com> - 40d4ffb7ec5dab4cfb32d6d19db8f45419742671 Fixed testCompile and testApi deprecations (#341) by sphill99 <s.phill99@gmail.com> - 7c767521db6aab17cb706d114570a557dc1c1efa Fix Android Studio project import of Volley. (#335) by Jeff Davidson <jpd@google.com> GitOrigin-RevId: ae701b33e718782e914108f9b6d1f1bb5f1ab7f8 Change-Id: I8f5792f679e88591c213156dcdd13482105e1c53
Diffstat (limited to 'src/main/java/com/android/volley/WaitingRequestManager.java')
-rw-r--r--src/main/java/com/android/volley/WaitingRequestManager.java176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/main/java/com/android/volley/WaitingRequestManager.java b/src/main/java/com/android/volley/WaitingRequestManager.java
new file mode 100644
index 0000000..682e339
--- /dev/null
+++ b/src/main/java/com/android/volley/WaitingRequestManager.java
@@ -0,0 +1,176 @@
+/*
+ * 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.android.volley;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * Callback to notify the caller when the network request returns. Valid responses can be used by
+ * all duplicate requests.
+ */
+class WaitingRequestManager implements Request.NetworkRequestCompleteListener {
+
+ /**
+ * Staging area for requests that already have a duplicate request in flight.
+ *
+ * <ul>
+ * <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache
+ * key.
+ * <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request
+ * is <em>not</em> contained in that list. Is null if no requests are staged.
+ * </ul>
+ */
+ private final Map<String, List<Request<?>>> mWaitingRequests = new HashMap<>();
+
+ private final ResponseDelivery mResponseDelivery;
+
+ /**
+ * RequestQueue that is passed in by the AsyncRequestQueue. This is null when this instance is
+ * initialized by the {@link CacheDispatcher}
+ */
+ @Nullable private final RequestQueue mRequestQueue;
+
+ /**
+ * CacheDispacter that is passed in by the CacheDispatcher. This is null when this instance is
+ * initialized by the {@link AsyncRequestQueue}
+ */
+ @Nullable private final CacheDispatcher mCacheDispatcher;
+
+ /**
+ * BlockingQueue that is passed in by the CacheDispatcher. This is null when this instance is
+ * initialized by the {@link AsyncRequestQueue}
+ */
+ @Nullable private final BlockingQueue<Request<?>> mNetworkQueue;
+
+ WaitingRequestManager(@NonNull RequestQueue requestQueue) {
+ mRequestQueue = requestQueue;
+ mResponseDelivery = mRequestQueue.getResponseDelivery();
+ mCacheDispatcher = null;
+ mNetworkQueue = null;
+ }
+
+ WaitingRequestManager(
+ @NonNull CacheDispatcher cacheDispatcher,
+ @NonNull BlockingQueue<Request<?>> networkQueue,
+ ResponseDelivery responseDelivery) {
+ mRequestQueue = null;
+ mResponseDelivery = responseDelivery;
+ mCacheDispatcher = cacheDispatcher;
+ mNetworkQueue = networkQueue;
+ }
+
+ /** Request received a valid response that can be used by other waiting requests. */
+ @Override
+ public void onResponseReceived(Request<?> request, Response<?> response) {
+ if (response.cacheEntry == null || response.cacheEntry.isExpired()) {
+ onNoUsableResponseReceived(request);
+ return;
+ }
+ String cacheKey = request.getCacheKey();
+ List<Request<?>> waitingRequests;
+ synchronized (this) {
+ waitingRequests = mWaitingRequests.remove(cacheKey);
+ }
+ if (waitingRequests != null) {
+ if (VolleyLog.DEBUG) {
+ VolleyLog.v(
+ "Releasing %d waiting requests for cacheKey=%s.",
+ waitingRequests.size(), cacheKey);
+ }
+ // Process all queued up requests.
+ for (Request<?> waiting : waitingRequests) {
+ mResponseDelivery.postResponse(waiting, response);
+ }
+ }
+ }
+
+ /** No valid response received from network, release waiting requests. */
+ @Override
+ public synchronized void onNoUsableResponseReceived(Request<?> request) {
+ String cacheKey = request.getCacheKey();
+ List<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);
+ if (waitingRequests != null && !waitingRequests.isEmpty()) {
+ if (VolleyLog.DEBUG) {
+ VolleyLog.v(
+ "%d waiting requests for cacheKey=%s; resend to network",
+ waitingRequests.size(), cacheKey);
+ }
+ Request<?> nextInLine = waitingRequests.remove(0);
+ mWaitingRequests.put(cacheKey, waitingRequests);
+ nextInLine.setNetworkRequestCompleteListener(this);
+ // RequestQueue will be non-null if this instance was created in AsyncRequestQueue.
+ if (mRequestQueue != null) {
+ // Will send the network request from the RequestQueue.
+ mRequestQueue.sendRequestOverNetwork(nextInLine);
+ } else if (mCacheDispatcher != null && mNetworkQueue != null) {
+ // If we're not using the AsyncRequestQueue, then submit it to the network queue.
+ try {
+ mNetworkQueue.put(nextInLine);
+ } catch (InterruptedException iex) {
+ VolleyLog.e("Couldn't add request to queue. %s", iex.toString());
+ // Restore the interrupted status of the calling thread (i.e. NetworkDispatcher)
+ Thread.currentThread().interrupt();
+ // Quit the current CacheDispatcher thread.
+ mCacheDispatcher.quit();
+ }
+ }
+ }
+ }
+
+ /**
+ * For cacheable requests, if a request for the same cache key is already in flight, add it to a
+ * queue to wait for that in-flight request to finish.
+ *
+ * @return whether the request was queued. If false, we should continue issuing the request over
+ * the network. If true, we should put the request on hold to be processed when the
+ * in-flight request finishes.
+ */
+ synchronized boolean maybeAddToWaitingRequests(Request<?> request) {
+ String cacheKey = request.getCacheKey();
+ // Insert request into stage if there's already a request with the same cache key
+ // in flight.
+ if (mWaitingRequests.containsKey(cacheKey)) {
+ // There is already a request in flight. Queue up.
+ List<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
+ if (stagedRequests == null) {
+ stagedRequests = new ArrayList<>();
+ }
+ request.addMarker("waiting-for-response");
+ stagedRequests.add(request);
+ mWaitingRequests.put(cacheKey, stagedRequests);
+ if (VolleyLog.DEBUG) {
+ VolleyLog.d("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
+ }
+ return true;
+ } else {
+ // Insert 'null' queue for this cacheKey, indicating there is now a request in
+ // flight.
+ mWaitingRequests.put(cacheKey, null);
+ request.setNetworkRequestCompleteListener(this);
+ if (VolleyLog.DEBUG) {
+ VolleyLog.d("new request, sending to network %s", cacheKey);
+ }
+ return false;
+ }
+ }
+}