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