diff options
Diffstat (limited to 'java/src/com/android/i18n/addressinput/CacheData.java')
-rw-r--r-- | java/src/com/android/i18n/addressinput/CacheData.java | 688 |
1 files changed, 344 insertions, 344 deletions
diff --git a/java/src/com/android/i18n/addressinput/CacheData.java b/java/src/com/android/i18n/addressinput/CacheData.java index 4f98e6f..39942c9 100644 --- a/java/src/com/android/i18n/addressinput/CacheData.java +++ b/java/src/com/android/i18n/addressinput/CacheData.java @@ -34,385 +34,385 @@ import java.util.HashSet; */ public final class CacheData { - /** - * Used to identify the source of a log message. - */ - private static final String TAG = "CacheData"; - - /** - * Time out value for the server to respond in millisecond. - */ - private static final int TIMEOUT = 5000; - - /** - * URL to get address data. You can also reset it by calling {@link #setUrl(String)}. - */ - private String mServiceUrl; - - /** - * Storage for all dynamically retrieved data. - */ - private final JsoMap mCache; - - /** - * CacheManager that handles caching that is needed by the client of the Address Widget. - */ - private final ClientCacheManager mClientCacheManager; - - /** - * All requests that have been sent. - */ - private final HashSet<String> mRequestedKeys = new HashSet<String>(); - - /** - * All invalid requested keys. For example, if we request a random string "asdfsdf9o", and the - * server responds by saying this key is invalid, it will be stored here. - */ - private final HashSet<String> mBadKeys = new HashSet<String>(); - - /** - * Temporary store for {@code CacheListener}s. When a key is requested and still waiting for - * server's response, the listeners for the same key will be temporary stored here. When the - * server responded, these listeners will be triggered and then removed. - */ - private final HashMap<LookupKey, HashSet<CacheListener>> mTemporaryListenerStore = - new HashMap<LookupKey, HashSet<CacheListener>>(); - - /** - * Creates an instance of CacheData with an empty cache, and uses no caching that is external - * to the AddressWidget. - */ - public CacheData() { - this(new SimpleClientCacheManager()); + /** + * Used to identify the source of a log message. + */ + private static final String TAG = "CacheData"; + + /** + * Time out value for the server to respond in millisecond. + */ + private static final int TIMEOUT = 5000; + + /** + * URL to get address data. You can also reset it by calling {@link #setUrl(String)}. + */ + private String serviceUrl; + + /** + * Storage for all dynamically retrieved data. + */ + private final JsoMap cache; + + /** + * CacheManager that handles caching that is needed by the client of the Address Widget. + */ + private final ClientCacheManager clientCacheManager; + + /** + * All requests that have been sent. + */ + private final HashSet<String> requestedKeys = new HashSet<String>(); + + /** + * All invalid requested keys. For example, if we request a random string "asdfsdf9o", and the + * server responds by saying this key is invalid, it will be stored here. + */ + private final HashSet<String> badKeys = new HashSet<String>(); + + /** + * Temporary store for {@code CacheListener}s. When a key is requested and still waiting for + * server's response, the listeners for the same key will be temporary stored here. When the + * server responded, these listeners will be triggered and then removed. + */ + private final HashMap<LookupKey, HashSet<CacheListener>> temporaryListenerStore = + new HashMap<LookupKey, HashSet<CacheListener>>(); + + /** + * Creates an instance of CacheData with an empty cache, and uses no caching that is external + * to the AddressWidget. + */ + public CacheData() { + this(new SimpleClientCacheManager()); + } + + /** + * Creates an instance of CacheData with an empty cache, and uses additional caching (external + * to the AddressWidget) specified by clientCacheManager. + */ + public CacheData(ClientCacheManager clientCacheManager) { + this.clientCacheManager = clientCacheManager; + setUrl(clientCacheManager.getAddressServerUrl()); + cache = JsoMap.createEmptyJsoMap(); + } + + /** + * This constructor is meant to be used together with external caching. + * + * Use case: + * + * After having finished using the address widget: + * String allCachedData = getJsonString(); + * Cache (save) allCachedData wherever makes sense for your service / activity + * + * Before using it next time: + * Get the saved allCachedData string + * new ClientData(new CacheData(allCachedData)) + * + * If you don't have any saved data you can either just pass an empty string to + * this constructor or use the other constructor. + * + * @param jsonString cached data from last time the class was used + */ + public CacheData(String jsonString) { + clientCacheManager = new SimpleClientCacheManager(); + setUrl(clientCacheManager.getAddressServerUrl()); + JsoMap tempMap = null; + try { + tempMap = JsoMap.buildJsoMap(jsonString); + } catch (JSONException jsonE) { + // If parsing the JSON string throws an exception, default to + // starting with an empty cache. + Log.w(TAG, "Could not parse json string, creating empty cache instead."); + tempMap = JsoMap.createEmptyJsoMap(); + } finally { + cache = tempMap; } + } - /** - * Creates an instance of CacheData with an empty cache, and uses additional caching (external - * to the AddressWidget) specified by clientCacheManager. - */ - public CacheData(ClientCacheManager clientCacheManager) { - mClientCacheManager = clientCacheManager; - setUrl(mClientCacheManager.getAddressServerUrl()); - mCache = JsoMap.createEmptyJsoMap(); - } + /** + * Interface for all listeners to {@link CacheData} change. This is only used when multiple + * requests of the same key is dispatched and server has not responded yet. + */ + private static interface CacheListener extends EventListener { /** - * This constructor is meant to be used together with external caching. - * - * Use case: - * - * After having finished using the address widget: - * String allCachedData = getJsonString(); - * Cache (save) allCachedData wherever makes sense for your service / activity - * - * Before using it next time: - * Get the saved allCachedData string - * new ClientData(new CacheData(allCachedData)) - * - * If you don't have any saved data you can either just pass an empty string to - * this constructor or use the other constructor. + * The function that will be called when valid data is about to be put in the cache. * - * @param jsonString cached data from last time the class was used + * @param key the key for newly arrived data. */ - public CacheData(String jsonString) { - mClientCacheManager = new SimpleClientCacheManager(); - setUrl(mClientCacheManager.getAddressServerUrl()); - JsoMap tempMap = null; - try { - tempMap = JsoMap.buildJsoMap(jsonString); - } catch (JSONException jsonE) { - // If parsing the JSON string throws an exception, default to - // starting with an empty cache. - Log.w(TAG, "Could not parse json string, creating empty cache instead."); - tempMap = JsoMap.createEmptyJsoMap(); - } finally { - mCache = tempMap; - } - } + void onAdd(String key); + } - /** - * Interface for all listeners to {@link CacheData} change. This is only used when multiple - * requests of the same key is dispatched and server has not responded yet. - */ - private static interface CacheListener extends EventListener { - - /** - * The function that will be called when valid data is about to be put in the cache. - * - * @param key the key for newly arrived data. - */ - void onAdd(String key); - } + /** + * Class to handle JSON response. + */ + private class JsonHandler { /** - * Class to handle JSON response. + * Key for the requested data. */ - private class JsonHandler { - - /** - * Key for the requested data. - */ - private final String mKey; - - /** - * Pre-existing data for the requested key. Null is allowed. - */ - private final JSONObject mExistingJso; - - private final DataLoadListener mListener; - - /** - * Constructs a JsonHandler instance. - * - * @param key The key for requested data. - * @param oldJso Pre-existing data for this key or null. - */ - private JsonHandler(String key, JSONObject oldJso, DataLoadListener listener) { - checkNotNull(key); - mKey = key; - mExistingJso = oldJso; - mListener = listener; - } - - /** - * Saves valid responded data to the cache once data arrives, or if the key is invalid, - * saves it in the invalid cache. If there is pre-existing data for the key, it will merge - * the new data will the old one. It also triggers {@link DataLoadListener#dataLoadingEnd()} - * method before it returns (even when the key is invalid, or input jso is null). This is - * called from a background thread. - * - * @param map The received JSON data as a map. - */ - private void handleJson(JsoMap map) { - // Can this ever happen? - if (map == null) { - Log.w(TAG, "server returns null for key:" + mKey); - mBadKeys.add(mKey); - notifyListenersAfterJobDone(mKey); - triggerDataLoadingEndIfNotNull(mListener); - return; - } - - JSONObject json = map; - String idKey = AddressDataKey.ID.name().toLowerCase(); - if (!json.has(idKey)) { - Log.w(TAG, "invalid or empty data returned for key: " + mKey); - mBadKeys.add(mKey); - notifyListenersAfterJobDone(mKey); - triggerDataLoadingEndIfNotNull(mListener); - return; - } - - if (mExistingJso != null) { - map.mergeData((JsoMap) mExistingJso); - } - - mCache.putObj(mKey, map); - notifyListenersAfterJobDone(mKey); - triggerDataLoadingEndIfNotNull(mListener); - } - } + private final String key; /** - * Sets address data server URL. Input URL cannot be null. - * - * @param url The service URL. + * Pre-existing data for the requested key. Null is allowed. */ - public void setUrl(String url) { - checkNotNull(url, "Cannot set URL of address data server to null."); - mServiceUrl = url; - } + private final JSONObject existingJso; - /** - * Gets address data server URL. - */ - public String getUrl() { - return mServiceUrl; - } + private final DataLoadListener listener; /** - * Returns a JSON string representing the data currently stored in this cache. It can be used - * to later create a new CacheData object containing the same cached data. + * Constructs a JsonHandler instance. * - * @return a JSON string representing the data stored in this cache + * @param key The key for requested data. + * @param oldJso Pre-existing data for this key or null. */ - public String getJsonString() { - return mCache.toString(); - } - - /** - * Checks if key and its value is cached (Note that only valid ones are cached). - */ - public boolean containsKey(String key) { - return mCache.containsKey(key); - } - - // This method is called from a background thread. - private void triggerDataLoadingEndIfNotNull(DataLoadListener listener) { - if (listener != null) { - listener.dataLoadingEnd(); - } + private JsonHandler(String key, JSONObject oldJso, DataLoadListener listener) { + checkNotNull(key); + this.key = key; + this.existingJso = oldJso; + this.listener = listener; } /** - * Fetches data from server, or returns if the data is already cached. If the fetched data is - * valid, it will be added to the cache. This method also triggers {@link - * DataLoadListener#dataLoadingEnd()} method before it returns. + * Saves valid responded data to the cache once data arrives, or if the key is invalid, + * saves it in the invalid cache. If there is pre-existing data for the key, it will merge + * the new data will the old one. It also triggers {@link DataLoadListener#dataLoadingEnd()} + * method before it returns (even when the key is invalid, or input jso is null). This is + * called from a background thread. * - * @param existingJso Pre-existing data for this key or null if none. - * @param listener An optional listener to call when done. + * @param map The received JSON data as a map. */ - void fetchDynamicData(final LookupKey key, JSONObject existingJso, - final DataLoadListener listener) { - checkNotNull(key, "null key not allowed."); - - if (listener != null) { - listener.dataLoadingBegin(); - } - - // Key is valid and cached. - if (mCache.containsKey(key.toString())) { - triggerDataLoadingEndIfNotNull(listener); - return; - } - - // Key is invalid and cached. - if (mBadKeys.contains(key.toString())) { - triggerDataLoadingEndIfNotNull(listener); - return; - } - - // Already requested the key, and is still waiting for server's response. - if (!mRequestedKeys.add(key.toString())) { - Log.d(TAG, "data for key " + key + " requested but not cached yet"); - addListenerToTempStore(key, new CacheListener() { - @Override - public void onAdd(String myKey) { - triggerDataLoadingEndIfNotNull(listener); - } - }); - return; - } - - // Key is in the cache maintained by the client of the AddressWidget. - String dataFromClientCache = mClientCacheManager.get(key.toString()); - if (dataFromClientCache != null && dataFromClientCache.length() > 0) { - final JsonHandler handler = new JsonHandler(key.toString(), - existingJso, listener); - try { - handler.handleJson(JsoMap.buildJsoMap(dataFromClientCache)); - return; - } catch (JSONException e) { - Log.w(TAG, "Data from client's cache is in the wrong format: " - + dataFromClientCache); - } - } - - // Key is not cached yet, now sending the request to the server. - JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); - jsonp.setTimeout(TIMEOUT); - final JsonHandler handler = new JsonHandler(key.toString(), - existingJso, listener); - jsonp.requestObject(mServiceUrl + "/" + key.toString(), - new AsyncCallback<JsoMap>() { - @Override - public void onFailure(Throwable caught) { - Log.w(TAG, "Request for key " + key + " failed"); - mRequestedKeys.remove(key.toString()); - notifyListenersAfterJobDone(key.toString()); - triggerDataLoadingEndIfNotNull(listener); - } - - @Override - public void onSuccess(JsoMap result) { - handler.handleJson(result); - // Put metadata into the cache maintained by the client of the - // AddressWidget. - String dataRetrieved = result.toString(); - mClientCacheManager.put(key.toString(), dataRetrieved); - } - }); + private void handleJson(JsoMap map) { + // Can this ever happen? + if (map == null) { + Log.w(TAG, "server returns null for key:" + key); + badKeys.add(key); + notifyListenersAfterJobDone(key); + triggerDataLoadingEndIfNotNull(listener); + return; + } + + JSONObject json = map; + String idKey = AddressDataKey.ID.name().toLowerCase(); + if (!json.has(idKey)) { + Log.w(TAG, "invalid or empty data returned for key: " + key); + badKeys.add(key); + notifyListenersAfterJobDone(key); + triggerDataLoadingEndIfNotNull(listener); + return; + } + + if (existingJso != null) { + map.mergeData((JsoMap) existingJso); + } + + cache.putObj(key, map); + notifyListenersAfterJobDone(key); + triggerDataLoadingEndIfNotNull(listener); } - - /** - * Gets region data from our compiled-in java file and stores it in the - * cache. This is only called when data cannot be obtained from the server, - * so there will be no pre-existing data for this key. - */ - void getFromRegionDataConstants(final LookupKey key) { - checkNotNull(key, "null key not allowed."); - String data = RegionDataConstants.getCountryFormatMap().get( - key.getValueForUpperLevelField(AddressField.COUNTRY)); - if (data != null) { - try { - mCache.putObj(key.toString(), JsoMap.buildJsoMap(data)); - } catch (JSONException e) { - Log.w(TAG, "Failed to parse data for key " + key + - " from RegionDataConstants"); - } - } + } + + /** + * Sets address data server URL. Input URL cannot be null. + * + * @param url The service URL. + */ + public void setUrl(String url) { + checkNotNull(url, "Cannot set URL of address data server to null."); + serviceUrl = url; + } + + /** + * Gets address data server URL. + */ + public String getUrl() { + return serviceUrl; + } + + /** + * Returns a JSON string representing the data currently stored in this cache. It can be used + * to later create a new CacheData object containing the same cached data. + * + * @return a JSON string representing the data stored in this cache + */ + public String getJsonString() { + return cache.toString(); + } + + /** + * Checks if key and its value is cached (Note that only valid ones are cached). + */ + public boolean containsKey(String key) { + return cache.containsKey(key); + } + + // This method is called from a background thread. + private void triggerDataLoadingEndIfNotNull(DataLoadListener listener) { + if (listener != null) { + listener.dataLoadingEnd(); } - - /** - * Retrieves string data identified by key. - * - * @param key Non-null key. E.g., "data/US/CA". - * @return String value for specified key. - */ - public String get(String key) { - checkNotNull(key, "null key not allowed"); - return mCache.get(key); + } + + /** + * Fetches data from server, or returns if the data is already cached. If the fetched data is + * valid, it will be added to the cache. This method also triggers {@link + * DataLoadListener#dataLoadingEnd()} method before it returns. + * + * @param existingJso Pre-existing data for this key or null if none. + * @param listener An optional listener to call when done. + */ + void fetchDynamicData(final LookupKey key, JSONObject existingJso, + final DataLoadListener listener) { + checkNotNull(key, "null key not allowed."); + + if (listener != null) { + listener.dataLoadingBegin(); } - /** - * Retrieves JsoMap data identified by key. - * - * @param key Non-null key. E.g., "data/US/CA". - * @return String value for specified key. - */ - public JsoMap getObj(String key) { - checkNotNull(key, "null key not allowed"); - return mCache.getObj(key); + // Key is valid and cached. + if (cache.containsKey(key.toString())) { + triggerDataLoadingEndIfNotNull(listener); + return; } - private void notifyListenersAfterJobDone(String key) { - LookupKey lookupKey = new LookupKey.Builder(key).build(); - HashSet<CacheListener> listeners = mTemporaryListenerStore.get(lookupKey); - if (listeners != null) { - for (CacheListener listener : listeners) { - listener.onAdd(key.toString()); - } - listeners.clear(); - } + // Key is invalid and cached. + if (badKeys.contains(key.toString())) { + triggerDataLoadingEndIfNotNull(listener); + return; } - private void addListenerToTempStore(LookupKey key, CacheListener listener) { - checkNotNull(key); - checkNotNull(listener); - HashSet<CacheListener> listeners = mTemporaryListenerStore.get(key); - if (listeners == null) { - listeners = new HashSet<CacheListener>(); - mTemporaryListenerStore.put(key, listeners); + // Already requested the key, and is still waiting for server's response. + if (!requestedKeys.add(key.toString())) { + Log.d(TAG, "data for key " + key + " requested but not cached yet"); + addListenerToTempStore(key, new CacheListener() { + @Override + public void onAdd(String myKey) { + triggerDataLoadingEndIfNotNull(listener); } - listeners.add(listener); + }); + return; } - /** - * Added for testing purposes. - * Adds a new object into the cache. - * @param id string of the format "data/country/.." ie. "data/US/CA" - * @param object The JSONObject to be put into cache. - */ - void addToJsoMap(String id, JSONObject object) { - mCache.putObj(id, object); + // Key is in the cache maintained by the client of the AddressWidget. + String dataFromClientCache = clientCacheManager.get(key.toString()); + if (dataFromClientCache != null && dataFromClientCache.length() > 0) { + final JsonHandler handler = new JsonHandler(key.toString(), + existingJso, listener); + try { + handler.handleJson(JsoMap.buildJsoMap(dataFromClientCache)); + return; + } catch (JSONException e) { + Log.w(TAG, "Data from client's cache is in the wrong format: " + + dataFromClientCache); + } } - /** - * Added for testing purposes. - * Checks to see if the cache is empty, - * @return true if the internal cache is empty - */ - boolean isEmpty() { - return mCache.length() == 0; + // Key is not cached yet, now sending the request to the server. + JsonpRequestBuilder jsonp = new JsonpRequestBuilder(); + jsonp.setTimeout(TIMEOUT); + final JsonHandler handler = new JsonHandler(key.toString(), + existingJso, listener); + jsonp.requestObject(serviceUrl + "/" + key.toString(), + new AsyncCallback<JsoMap>() { + @Override + public void onFailure(Throwable caught) { + Log.w(TAG, "Request for key " + key + " failed"); + requestedKeys.remove(key.toString()); + notifyListenersAfterJobDone(key.toString()); + triggerDataLoadingEndIfNotNull(listener); + } + + @Override + public void onSuccess(JsoMap result) { + handler.handleJson(result); + // Put metadata into the cache maintained by the client of the + // AddressWidget. + String dataRetrieved = result.toString(); + clientCacheManager.put(key.toString(), dataRetrieved); + } + }); + } + + /** + * Gets region data from our compiled-in java file and stores it in the + * cache. This is only called when data cannot be obtained from the server, + * so there will be no pre-existing data for this key. + */ + void getFromRegionDataConstants(final LookupKey key) { + checkNotNull(key, "null key not allowed."); + String data = RegionDataConstants.getCountryFormatMap().get( + key.getValueForUpperLevelField(AddressField.COUNTRY)); + if (data != null) { + try { + cache.putObj(key.toString(), JsoMap.buildJsoMap(data)); + } catch (JSONException e) { + Log.w(TAG, "Failed to parse data for key " + key + + " from RegionDataConstants"); + } + } + } + + /** + * Retrieves string data identified by key. + * + * @param key Non-null key. E.g., "data/US/CA". + * @return String value for specified key. + */ + public String get(String key) { + checkNotNull(key, "null key not allowed"); + return cache.get(key); + } + + /** + * Retrieves JsoMap data identified by key. + * + * @param key Non-null key. E.g., "data/US/CA". + * @return String value for specified key. + */ + public JsoMap getObj(String key) { + checkNotNull(key, "null key not allowed"); + return cache.getObj(key); + } + + private void notifyListenersAfterJobDone(String key) { + LookupKey lookupKey = new LookupKey.Builder(key).build(); + HashSet<CacheListener> listeners = temporaryListenerStore.get(lookupKey); + if (listeners != null) { + for (CacheListener listener : listeners) { + listener.onAdd(key.toString()); + } + listeners.clear(); + } + } + + private void addListenerToTempStore(LookupKey key, CacheListener listener) { + checkNotNull(key); + checkNotNull(listener); + HashSet<CacheListener> listeners = temporaryListenerStore.get(key); + if (listeners == null) { + listeners = new HashSet<CacheListener>(); + temporaryListenerStore.put(key, listeners); } + listeners.add(listener); + } + + /** + * Added for testing purposes. + * Adds a new object into the cache. + * @param id string of the format "data/country/.." ie. "data/US/CA" + * @param object The JSONObject to be put into cache. + */ + void addToJsoMap(String id, JSONObject object) { + cache.putObj(id, object); + } + + /** + * Added for testing purposes. + * Checks to see if the cache is empty, + * @return true if the internal cache is empty + */ + boolean isEmpty() { + return cache.length() == 0; + } } |