|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.sync; |
|
6 |
|
7 import java.util.Collections; |
|
8 import java.util.HashMap; |
|
9 import java.util.Map; |
|
10 import java.util.Map.Entry; |
|
11 |
|
12 import org.mozilla.gecko.background.common.log.Logger; |
|
13 |
|
14 /** |
|
15 * Fetches the timestamp information in <code>info/collections</code> on the |
|
16 * Sync server. Provides access to those timestamps, along with logic to check |
|
17 * for whether a collection requires an update. |
|
18 */ |
|
19 public class InfoCollections { |
|
20 private static final String LOG_TAG = "InfoCollections"; |
|
21 |
|
22 /** |
|
23 * Fields fetched from the server, or <code>null</code> if not yet fetched. |
|
24 * <p> |
|
25 * Rather than storing decimal/double timestamps, as provided by the server, |
|
26 * we convert immediately to milliseconds since epoch. |
|
27 */ |
|
28 final Map<String, Long> timestamps; |
|
29 |
|
30 public InfoCollections() { |
|
31 this(new ExtendedJSONObject()); |
|
32 } |
|
33 |
|
34 public InfoCollections(final ExtendedJSONObject record) { |
|
35 Logger.debug(LOG_TAG, "info/collections is " + record.toJSONString()); |
|
36 HashMap<String, Long> map = new HashMap<String, Long>(); |
|
37 |
|
38 for (Entry<String, Object> entry : record.entrySet()) { |
|
39 final String key = entry.getKey(); |
|
40 final Object value = entry.getValue(); |
|
41 |
|
42 // These objects are most likely going to be Doubles. Regardless, we |
|
43 // want to get them in a more sane time format. |
|
44 if (value instanceof Double) { |
|
45 map.put(key, Utils.decimalSecondsToMilliseconds((Double) value)); |
|
46 continue; |
|
47 } |
|
48 if (value instanceof Long) { |
|
49 map.put(key, Utils.decimalSecondsToMilliseconds((Long) value)); |
|
50 continue; |
|
51 } |
|
52 if (value instanceof Integer) { |
|
53 map.put(key, Utils.decimalSecondsToMilliseconds((Integer) value)); |
|
54 continue; |
|
55 } |
|
56 Logger.warn(LOG_TAG, "Skipping info/collections entry for " + key); |
|
57 } |
|
58 |
|
59 this.timestamps = Collections.unmodifiableMap(map); |
|
60 } |
|
61 |
|
62 /** |
|
63 * Return the timestamp for the given collection, or null if the timestamps |
|
64 * have not been fetched or the given collection does not have a timestamp. |
|
65 * |
|
66 * @param collection |
|
67 * The collection to inspect. |
|
68 * @return the timestamp in milliseconds since epoch. |
|
69 */ |
|
70 public Long getTimestamp(String collection) { |
|
71 if (timestamps == null) { |
|
72 return null; |
|
73 } |
|
74 return timestamps.get(collection); |
|
75 } |
|
76 |
|
77 /** |
|
78 * Test if a given collection needs to be updated. |
|
79 * |
|
80 * @param collection |
|
81 * The collection to test. |
|
82 * @param lastModified |
|
83 * Timestamp when local record was last modified. |
|
84 */ |
|
85 public boolean updateNeeded(String collection, long lastModified) { |
|
86 Logger.trace(LOG_TAG, "Testing " + collection + " for updateNeeded. Local last modified is " + lastModified + "."); |
|
87 |
|
88 // No local record of modification time? Need an update. |
|
89 if (lastModified <= 0) { |
|
90 return true; |
|
91 } |
|
92 |
|
93 // No meta/global on the server? We need an update. The server fetch will fail and |
|
94 // then we will upload a fresh meta/global. |
|
95 Long serverLastModified = getTimestamp(collection); |
|
96 if (serverLastModified == null) { |
|
97 return true; |
|
98 } |
|
99 |
|
100 // Otherwise, we need an update if our modification time is stale. |
|
101 return (serverLastModified.longValue() > lastModified); |
|
102 } |
|
103 } |