1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/sync/InfoCollections.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,103 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.sync; 1.9 + 1.10 +import java.util.Collections; 1.11 +import java.util.HashMap; 1.12 +import java.util.Map; 1.13 +import java.util.Map.Entry; 1.14 + 1.15 +import org.mozilla.gecko.background.common.log.Logger; 1.16 + 1.17 +/** 1.18 + * Fetches the timestamp information in <code>info/collections</code> on the 1.19 + * Sync server. Provides access to those timestamps, along with logic to check 1.20 + * for whether a collection requires an update. 1.21 + */ 1.22 +public class InfoCollections { 1.23 + private static final String LOG_TAG = "InfoCollections"; 1.24 + 1.25 + /** 1.26 + * Fields fetched from the server, or <code>null</code> if not yet fetched. 1.27 + * <p> 1.28 + * Rather than storing decimal/double timestamps, as provided by the server, 1.29 + * we convert immediately to milliseconds since epoch. 1.30 + */ 1.31 + final Map<String, Long> timestamps; 1.32 + 1.33 + public InfoCollections() { 1.34 + this(new ExtendedJSONObject()); 1.35 + } 1.36 + 1.37 + public InfoCollections(final ExtendedJSONObject record) { 1.38 + Logger.debug(LOG_TAG, "info/collections is " + record.toJSONString()); 1.39 + HashMap<String, Long> map = new HashMap<String, Long>(); 1.40 + 1.41 + for (Entry<String, Object> entry : record.entrySet()) { 1.42 + final String key = entry.getKey(); 1.43 + final Object value = entry.getValue(); 1.44 + 1.45 + // These objects are most likely going to be Doubles. Regardless, we 1.46 + // want to get them in a more sane time format. 1.47 + if (value instanceof Double) { 1.48 + map.put(key, Utils.decimalSecondsToMilliseconds((Double) value)); 1.49 + continue; 1.50 + } 1.51 + if (value instanceof Long) { 1.52 + map.put(key, Utils.decimalSecondsToMilliseconds((Long) value)); 1.53 + continue; 1.54 + } 1.55 + if (value instanceof Integer) { 1.56 + map.put(key, Utils.decimalSecondsToMilliseconds((Integer) value)); 1.57 + continue; 1.58 + } 1.59 + Logger.warn(LOG_TAG, "Skipping info/collections entry for " + key); 1.60 + } 1.61 + 1.62 + this.timestamps = Collections.unmodifiableMap(map); 1.63 + } 1.64 + 1.65 + /** 1.66 + * Return the timestamp for the given collection, or null if the timestamps 1.67 + * have not been fetched or the given collection does not have a timestamp. 1.68 + * 1.69 + * @param collection 1.70 + * The collection to inspect. 1.71 + * @return the timestamp in milliseconds since epoch. 1.72 + */ 1.73 + public Long getTimestamp(String collection) { 1.74 + if (timestamps == null) { 1.75 + return null; 1.76 + } 1.77 + return timestamps.get(collection); 1.78 + } 1.79 + 1.80 + /** 1.81 + * Test if a given collection needs to be updated. 1.82 + * 1.83 + * @param collection 1.84 + * The collection to test. 1.85 + * @param lastModified 1.86 + * Timestamp when local record was last modified. 1.87 + */ 1.88 + public boolean updateNeeded(String collection, long lastModified) { 1.89 + Logger.trace(LOG_TAG, "Testing " + collection + " for updateNeeded. Local last modified is " + lastModified + "."); 1.90 + 1.91 + // No local record of modification time? Need an update. 1.92 + if (lastModified <= 0) { 1.93 + return true; 1.94 + } 1.95 + 1.96 + // No meta/global on the server? We need an update. The server fetch will fail and 1.97 + // then we will upload a fresh meta/global. 1.98 + Long serverLastModified = getTimestamp(collection); 1.99 + if (serverLastModified == null) { 1.100 + return true; 1.101 + } 1.102 + 1.103 + // Otherwise, we need an update if our modification time is stale. 1.104 + return (serverLastModified.longValue() > lastModified); 1.105 + } 1.106 +}