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 cache triage on a queue of requests. 233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Requests added to the specified cache queue are resolved from cache. 253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Any deliverable response is posted back to the caller via a 263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * {@link ResponseDelivery}. Cache misses and responses that require 273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * refresh are enqueued on the specified network queue for processing 283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * by a {@link NetworkDispatcher}. 293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick@SuppressWarnings("rawtypes") 313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrickpublic class CacheDispatcher extends Thread { 323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private static final boolean DEBUG = VolleyLog.DEBUG; 343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** The queue of requests coming in for triage. */ 363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final BlockingQueue<Request> mCacheQueue; 373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** The queue of requests going out to the network. */ 393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final BlockingQueue<Request> mNetworkQueue; 403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** The cache to read from. */ 423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final Cache mCache; 433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** For posting responses. */ 453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private final ResponseDelivery mDelivery; 463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** Used for telling us to die. */ 483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick private volatile boolean mQuit = false; 493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Creates a new cache triage dispatcher thread. You must call {@link #start()} 523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * in order to begin processing. 533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * 543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param cacheQueue Queue of incoming requests for triage 553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param networkQueue Queue to post requests that require network to 563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param cache Cache interface to use for resolution 573713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * @param delivery Delivery interface to use for posting responses 583713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 593713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public CacheDispatcher( 603713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue, 613713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Cache cache, ResponseDelivery delivery) { 623713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mCacheQueue = cacheQueue; 633713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue = networkQueue; 643713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mCache = cache; 653713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mDelivery = delivery; 663713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 673713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 683713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick /** 693713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * Forces this dispatcher to quit immediately. If any requests are still in 703713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick * the queue, they are not guaranteed to be processed. 713713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick */ 723713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public void quit() { 733713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mQuit = true; 743713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick interrupt(); 753713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 763713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 773713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick @Override 783713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public void run() { 793713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (DEBUG) VolleyLog.v("start new dispatcher"); 803713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 813713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Make a blocking call to initialize the cache. 823713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mCache.initialize(); 833713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 843713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick while (true) { 853713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick try { 863713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Get a request from the cache triage queue, blocking until 873713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // at least one is available. 883713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick final Request request = mCacheQueue.take(); 893713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-queue-take"); 903713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 913713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // If the request has been canceled, don't bother dispatching it. 923713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (request.isCanceled()) { 933713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.finish("cache-discard-canceled"); 943713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 953713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 963713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 973713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Attempt to retrieve this item from cache. 983713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Cache.Entry entry = mCache.get(request.getCacheKey()); 993713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (entry == null) { 1003713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-miss"); 1013713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Cache miss; send off to the network dispatcher. 1023713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue.put(request); 1033713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 1043713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1053713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1063713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // If it is completely expired, just send it to the network. 1073713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (entry.isExpired()) { 1083713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit-expired"); 1093713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.setCacheEntry(entry); 1103713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue.put(request); 1113713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 1123713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1133713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1143713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // We have a cache hit; parse its data for delivery back to the request. 1153713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit"); 1163713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick Response<?> response = request.parseNetworkResponse( 1173713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick new NetworkResponse(entry.data)); 1183713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit-parsed"); 1193713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1203713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (!entry.refreshNeeded()) { 1213713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Completely unexpired cache hit. Just deliver the response. 1223713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mDelivery.postResponse(request, response); 1233713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } else { 1243713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Soft-expired cache hit. We can deliver the cached response, 1253713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // but we need to also send the request to the network for 1263713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // refreshing. 1273713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.addMarker("cache-hit-refresh-needed"); 1283713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick request.setCacheEntry(entry); 1293713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1303713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Mark the response as intermediate. 1313713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick response.intermediate = true; 1323713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1333713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Post the intermediate response back to the user and have 1343713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // the delivery then forward the request along to the network. 1353713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mDelivery.postResponse(request, response, new Runnable() { 1363713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick @Override 1373713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick public void run() { 1383713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick try { 1393713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick mNetworkQueue.put(request); 1403713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } catch (InterruptedException e) { 1413713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // Not much we can do about this. 1423713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1433713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1443713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick }); 1453713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1463713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick 1473713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } catch (InterruptedException e) { 1483713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick // We may have been interrupted because it was time to quit. 1493713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick if (mQuit) { 1503713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick return; 1513713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1523713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick continue; 1533713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1543713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1553713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick } 1563713094c56d25e25df2a508dbee4aea869ffdea1Ficus Kirkpatrick} 157