13713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/*
23713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Copyright (C) 2011 The Android Open Source Project
33713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
43713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Licensed under the Apache License, Version 2.0 (the "License");
53713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * you may not use this file except in compliance with the License.
63713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * You may obtain a copy of the License at
73713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
83713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *      http://www.apache.org/licenses/LICENSE-2.0
93713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Unless required by applicable law or agreed to in writing, software
113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * distributed under the License is distributed on an "AS IS" BASIS,
123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * See the License for the specific language governing permissions and
143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * limitations under the License.
153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */
163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpackage com.android.volley;
183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickimport java.util.concurrent.BlockingQueue;
203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick/**
223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Provides a thread for performing network dispatch from a queue of requests.
233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick *
243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Requests added to the specified queue are processed from the network via a
253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * specified {@link Network} interface. Responses are committed to cache, if
263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * eligible, using a specified {@link Cache} interface. Valid responses and
273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * errors are posted back to the caller via a {@link ResponseDelivery}.
283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */
293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick@SuppressWarnings("rawtypes")
303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class NetworkDispatcher extends Thread {
313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /** The queue of requests to service. */
323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private final BlockingQueue<Request> mQueue;
333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /** The network interface for processing requests. */
343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private final Network mNetwork;
353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /** The cache to write to. */
363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private final Cache mCache;
373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /** For posting responses and errors. */
383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private final ResponseDelivery mDelivery;
393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /** Used for telling us to die. */
403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private volatile boolean mQuit = false;
413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * Creates a new network dispatcher thread.  You must call {@link #start()}
443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * in order to begin processing.
453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     *
463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * @param queue Queue of incoming requests for triage
473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * @param network Network interface to use for performing requests
483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * @param cache Cache interface to use for writing responses to cache
493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * @param delivery Delivery interface to use for posting responses
503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public NetworkDispatcher(BlockingQueue<Request> queue,
523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            Network network, Cache cache,
533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            ResponseDelivery delivery) {
543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mQueue = queue;
553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mNetwork = network;
563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mCache = cache;
573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mDelivery = delivery;
583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    /**
613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * Forces this dispatcher to quit immediately.  If any requests are still in
623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     * the queue, they are not guaranteed to be processed.
633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick     */
643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void quit() {
653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mQuit = true;
663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        interrupt();
673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    @Override
703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    public void run() {
713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        Request request;
723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        while (true) {
733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            try {
743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Take a request from the queue.
753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                request = mQueue.take();
763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (InterruptedException e) {
773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // We may have been interrupted because it was time to quit.
783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (mQuit) {
793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    return;
803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                continue;
823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            try {
853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                request.addMarker("network-queue-take");
863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // If the request was cancelled already, do not perform the
883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // network request.
893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (request.isCanceled()) {
903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    request.finish("network-discard-cancelled");
913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    continue;
923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Perform the network request.
953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                NetworkResponse networkResponse = mNetwork.performRequest(request);
963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                request.addMarker("network-http-complete");
973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // If the server returned 304 AND we delivered a response already,
993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // we're done -- don't deliver a second identical response.
1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    request.finish("not-modified");
1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    continue;
1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Parse the response here on the worker thread.
1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                Response<?> response = request.parseNetworkResponse(networkResponse);
1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                request.addMarker("network-parse-complete");
1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Write to cache if applicable.
1103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // TODO: Only update cache metadata instead of entire record for 304s.
1113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                if (request.shouldCache() && response.cacheEntry != null) {
1123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    mCache.put(request.getCacheKey(), response.cacheEntry);
1133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                    request.addMarker("network-cache-written");
1143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                }
1153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                // Post the response back.
1173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                request.markDelivered();
1183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                mDelivery.postResponse(request, response);
1193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (VolleyError volleyError) {
1203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                parseAndDeliverNetworkError(request, volleyError);
1213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            } catch (Exception e) {
1223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                VolleyLog.e("Unhandled exception %s", e.toString());
1233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick                mDelivery.postError(request, new VolleyError(e));
1243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick            }
1253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        }
1263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick
1283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
1293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        error = request.parseNetworkError(error);
1303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick        mDelivery.postError(request, error);
1313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick    }
1323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick}
133