1d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/*
2d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Copyright (C) 2011 The Android Open Source Project
3d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru *
4d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License");
5d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * you may not use this file except in compliance with the License.
6d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * You may obtain a copy of the License at
7d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru *
8d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru *      http://www.apache.org/licenses/LICENSE-2.0
9d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru *
10d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software
11d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS,
12d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * See the License for the specific language governing permissions and
14d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * limitations under the License.
15d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */
16d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
17d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupackage com.android.volley;
18d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
19d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport android.os.Handler;
20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport android.os.Looper;
21d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
2258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabotimport java.util.ArrayList;
23d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.HashMap;
24d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.HashSet;
25d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.LinkedList;
2658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabotimport java.util.List;
27d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Map;
28d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Queue;
29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Set;
30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.concurrent.PriorityBlockingQueue;
31d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.concurrent.atomic.AtomicInteger;
32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
33d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/**
34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * A request dispatch queue with a thread pool of dispatchers.
35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru *
36d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Calling {@link #add(Request)} will enqueue the given Request for dispatch,
37d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * resolving from either cache or network on a worker thread, and then delivering
38d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * a parsed response on the main thread.
39d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */
40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupublic class RequestQueue {
41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
4258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    /** Callback interface for completed requests. */
4358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    public static interface RequestFinishedListener<T> {
4458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot        /** Called when a request has finished processing. */
4558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot        public void onRequestFinished(Request<T> request);
4658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    }
4758f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot
48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** Used for generating monotonically-increasing sequence numbers for requests. */
496772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru    private AtomicInteger mSequenceGenerator = new AtomicInteger();
50d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
51d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Staging area for requests that already have a duplicate request in flight.
53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
54d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * <ul>
55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *     <li>containsKey(cacheKey) indicates that there is a request in flight for the given cache
56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *          key.</li>
57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *     <li>get(cacheKey) returns waiting requests for the given cache key. The in flight request
58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *          is <em>not</em> contained in that list. Is null if no requests are staged.</li>
59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * </ul>
60d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
6135d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick    private final Map<String, Queue<Request<?>>> mWaitingRequests =
6235d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick            new HashMap<String, Queue<Request<?>>>();
63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
65d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * The set of all requests currently being processed by this RequestQueue. A Request
66d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * will be in this set if it is waiting in any queue or currently being processed by
67d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * any dispatcher.
68d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
6935d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
70d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
71d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** The cache triage queue. */
7235d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick    private final PriorityBlockingQueue<Request<?>> mCacheQueue =
7335d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick        new PriorityBlockingQueue<Request<?>>();
74d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
75d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** The queue of requests that are actually going out to the network. */
7635d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
7735d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick        new PriorityBlockingQueue<Request<?>>();
78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** Number of network request dispatcher threads to start. */
80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
8235d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick    /** Cache interface for retrieving and storing responses. */
83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private final Cache mCache;
84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
85d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** Network interface for performing requests. */
86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private final Network mNetwork;
87d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
88d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** Response delivery mechanism. */
89d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private final ResponseDelivery mDelivery;
90d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
91d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** The network dispatchers. */
92d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private NetworkDispatcher[] mDispatchers;
93d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
94d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /** The cache dispatcher. */
95d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    private CacheDispatcher mCacheDispatcher;
96d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
9758f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    private List<RequestFinishedListener> mFinishedListeners =
9858f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot            new ArrayList<RequestFinishedListener>();
9958f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot
100d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
101d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Creates the worker pool. Processing will not begin until {@link #start()} is called.
102d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
103d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param cache A Cache to use for persisting responses to disk
104d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param network A Network interface for performing HTTP requests
105d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param threadPoolSize Number of network dispatcher threads to create
106d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param delivery A ResponseDelivery interface for posting responses and errors
107d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
108d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public RequestQueue(Cache cache, Network network, int threadPoolSize,
109d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            ResponseDelivery delivery) {
110d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mCache = cache;
111d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mNetwork = network;
112d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mDispatchers = new NetworkDispatcher[threadPoolSize];
113d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mDelivery = delivery;
114d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
115d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
116d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
117d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Creates the worker pool. Processing will not begin until {@link #start()} is called.
118d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
119d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param cache A Cache to use for persisting responses to disk
120d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param network A Network interface for performing HTTP requests
121d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param threadPoolSize Number of network dispatcher threads to create
122d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
123d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public RequestQueue(Cache cache, Network network, int threadPoolSize) {
124d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        this(cache, network, threadPoolSize,
125d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                new ExecutorDelivery(new Handler(Looper.getMainLooper())));
126d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
127d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
128d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
129d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Creates the worker pool. Processing will not begin until {@link #start()} is called.
130d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
131d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param cache A Cache to use for persisting responses to disk
132d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param network A Network interface for performing HTTP requests
133d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
134d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public RequestQueue(Cache cache, Network network) {
135d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
136d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
137d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
138d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
139d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Starts the dispatchers in this queue.
140d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
141d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public void start() {
142d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        stop();  // Make sure any currently running dispatchers are stopped.
143d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // Create the cache dispatcher and start it.
144d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
145d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        mCacheDispatcher.start();
146d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
147d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // Create network dispatchers (and corresponding threads) up to the pool size.
148d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        for (int i = 0; i < mDispatchers.length; i++) {
149d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
150d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    mCache, mDelivery);
151d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mDispatchers[i] = networkDispatcher;
152d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            networkDispatcher.start();
153d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
154d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
155d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
156d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
157d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Stops the cache and network dispatchers.
158d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
159d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public void stop() {
160d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        if (mCacheDispatcher != null) {
161d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mCacheDispatcher.quit();
162d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
163d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        for (int i = 0; i < mDispatchers.length; i++) {
164d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            if (mDispatchers[i] != null) {
165d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mDispatchers[i].quit();
166d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            }
167d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
168d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
169d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
170d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
171d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Gets a sequence number.
172d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
1736772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru    public int getSequenceNumber() {
1746772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru        return mSequenceGenerator.incrementAndGet();
175d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
176d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
177d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
1780acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton     * Gets the {@link Cache} instance being used.
1790acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton     */
1800acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton    public Cache getCache() {
1810acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton        return mCache;
1820acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton    }
1830acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton
1840acc7936feb3deb2b969b568b07f3bf96caf0076Evan Charlton    /**
185d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * A simple predicate or filter interface for Requests, for use by
186d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * {@link RequestQueue#cancelAll(RequestFilter)}.
187d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
188d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public interface RequestFilter {
189d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        public boolean apply(Request<?> request);
190d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
191d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
192d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
193d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Cancels all requests in this queue for which the given filter applies.
194d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param filter The filtering function to use
195d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
196d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public void cancelAll(RequestFilter filter) {
197d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        synchronized (mCurrentRequests) {
198d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            for (Request<?> request : mCurrentRequests) {
199d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                if (filter.apply(request)) {
200d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    request.cancel();
201d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                }
202d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            }
203d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
204d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
205d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
206d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
207d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Cancels all requests in this queue with the given tag. Tag must be non-null
208d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * and equality is by identity.
209d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
210d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    public void cancelAll(final Object tag) {
211d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        if (tag == null) {
212d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            throw new IllegalArgumentException("Cannot cancelAll with a null tag");
213d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
214d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        cancelAll(new RequestFilter() {
215d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            @Override
216d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            public boolean apply(Request<?> request) {
217d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                return request.getTag() == tag;
218d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            }
219d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        });
220d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
221d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
222d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
223d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Adds a Request to the dispatch queue.
224d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @param request The request to service
225d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * @return The passed-in request
226d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
227393504e5d9aaf1c79c52df482b70e3f80ac50765Max Cai    public <T> Request<T> add(Request<T> request) {
228d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // Tag the request as belonging to this queue and add it to the set of current requests.
229d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        request.setRequestQueue(this);
230d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        synchronized (mCurrentRequests) {
231d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mCurrentRequests.add(request);
232d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
233d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
234d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // Process requests in the order they are added.
2356772bce3d3322ccbcf6481545ffe895d5d401b39Jean-Baptiste Queru        request.setSequence(getSequenceNumber());
236d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        request.addMarker("add-to-queue");
237d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
238d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // If the request is uncacheable, skip the cache queue and go straight to the network.
239d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        if (!request.shouldCache()) {
240d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mNetworkQueue.add(request);
241d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            return request;
242d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
243d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
244d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // Insert request into stage if there's already a request with the same cache key in flight.
245d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        synchronized (mWaitingRequests) {
246d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            String cacheKey = request.getCacheKey();
247d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            if (mWaitingRequests.containsKey(cacheKey)) {
248d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                // There is already a request in flight. Queue up.
24935d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
250d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                if (stagedRequests == null) {
25135d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick                    stagedRequests = new LinkedList<Request<?>>();
252d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                }
253d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                stagedRequests.add(request);
254d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mWaitingRequests.put(cacheKey, stagedRequests);
255d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                if (VolleyLog.DEBUG) {
256d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
257d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                }
258d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            } else {
259d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                // Insert 'null' queue for this cacheKey, indicating there is now a request in
260d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                // flight.
261d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mWaitingRequests.put(cacheKey, null);
262d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                mCacheQueue.add(request);
263d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            }
264d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            return request;
265d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
266d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
267d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
268d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    /**
269d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * Called from {@link Request#finish(String)}, indicating that processing of the given request
270d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * has finished.
271d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *
272d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     * <p>Releases waiting requests for <code>request.getCacheKey()</code> if
273d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     *      <code>request.shouldCache()</code>.</p>
274d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru     */
27558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    <T> void finish(Request<T> request) {
276d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        // Remove from the set of requests currently being processed.
277d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        synchronized (mCurrentRequests) {
278d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            mCurrentRequests.remove(request);
279d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
28058f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot        synchronized (mFinishedListeners) {
28158f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot          for (RequestFinishedListener<T> listener : mFinishedListeners) {
28258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot            listener.onRequestFinished(request);
28358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot          }
28458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot        }
285d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru
286d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        if (request.shouldCache()) {
287d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            synchronized (mWaitingRequests) {
288d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                String cacheKey = request.getCacheKey();
28935d5cc345a7bc5c7391aeda3d3fce711c6376c7bFicus Kirkpatrick                Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);
290d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                if (waitingRequests != null) {
291d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    if (VolleyLog.DEBUG) {
292d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                        VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.",
293d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                                waitingRequests.size(), cacheKey);
294d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    }
295d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    // Process all queued up requests. They won't be considered as in flight, but
296d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    // that's not a problem as the cache has been primed by 'request'.
297d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                    mCacheQueue.addAll(waitingRequests);
298d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru                }
299d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru            }
300d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru        }
301d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru    }
30258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot
30358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    public  <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) {
30458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot      synchronized (mFinishedListeners) {
30558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot        mFinishedListeners.add(listener);
30658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot      }
30758f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    }
30858f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot
30958f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    /**
31058f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot     * Remove a RequestFinishedListener. Has no effect if listener was not previously added.
31158f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot     */
31258f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    public  <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) {
31358f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot      synchronized (mFinishedListeners) {
31458f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot        mFinishedListeners.remove(listener);
31558f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot      }
31658f9c05b9ad88512bd4da9d8e27df2e834a06b38Brett Chabot    }
317d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru}
318