source: josm/trunk/src/org/openstreetmap/josm/io/CacheCustomContent.java@ 8148

Last change on this file since 8148 was 7434, checked in by Don-vip, 10 years ago

fix #8885 (see #4614) - add offline mode with new command line argument --offline which can take one of several of these values (comma separated):

  • josm_website: to disable all accesses to JOSM website (when not cached, disables Getting Started page, help, plugin list, styles, imagery, presets, rules)
  • osm_api: to disable all accesses to OSM API (disables download, upload, changeset queries, history, user message notification)
  • all: alias to disable all values. Currently equivalent to "josm_website,osm_api"

Plus improved javadoc, fixed EDT violations, and fixed a bug with HTTP redirection sent without "Location" header

  • Property svn:eol-style set to native
File size: 5.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import java.io.BufferedInputStream;
5import java.io.BufferedOutputStream;
6import java.io.File;
7import java.io.FileInputStream;
8import java.io.FileOutputStream;
9import java.io.IOException;
10import java.nio.charset.StandardCharsets;
11
12import org.openstreetmap.josm.Main;
13
14/**
15 * Use this class if you want to cache and store a single file that gets updated regularly.
16 * Unless you flush() it will be kept in memory. If you want to cache a lot of data and/or files,
17 * use CacheFiles
18 * @param <T> a {@link Throwable} that may be thrown during {@link #updateData()},
19 * use {@link RuntimeException} if no exception must be handled.
20 * @author xeen
21 *
22 */
23public abstract class CacheCustomContent<T extends Throwable> {
24 /**
25 * Common intervals
26 */
27 public static final int INTERVAL_ALWAYS = -1;
28 public static final int INTERVAL_HOURLY = 60*60;
29 public static final int INTERVAL_DAILY = INTERVAL_HOURLY * 24;
30 public static final int INTERVAL_WEEKLY = INTERVAL_DAILY * 7;
31 public static final int INTERVAL_MONTHLY = INTERVAL_WEEKLY * 4;
32 public static final int INTERVAL_NEVER = Integer.MAX_VALUE;
33
34 /**
35 * Where the data will be stored
36 */
37 private byte[] data = null;
38
39 /**
40 * The ident that identifies the stored file. Includes file-ending.
41 */
42 private final String ident;
43
44 /**
45 * The (file-)path where the data will be stored
46 */
47 private final File path;
48
49 /**
50 * How often to update the cached version
51 */
52 private final int updateInterval;
53
54 /**
55 * This function will be executed when an update is required. It has to be implemented by the
56 * inheriting class and should use a worker if it has a long wall time as the function is
57 * executed in the current thread.
58 * @return the data to cache
59 */
60 protected abstract byte[] updateData() throws T;
61
62 /**
63 * This function serves as a comfort hook to perform additional checks if the cache is valid
64 * @return True if the cached copy is still valid
65 */
66 protected boolean isCacheValid() {
67 return true;
68 }
69
70 /**
71 * Initializes the class. Note that all read data will be stored in memory until it is flushed
72 * by flushData().
73 * @param ident
74 * @param updateInterval
75 */
76 public CacheCustomContent(String ident, int updateInterval) {
77 this.ident = ident;
78 this.updateInterval = updateInterval;
79 this.path = new File(Main.pref.getCacheDirectory(), ident);
80 }
81
82 private boolean needsUpdate() {
83 if (isOffline()) {
84 return false;
85 }
86 return Main.pref.getInteger("cache." + ident, 0) + updateInterval < System.currentTimeMillis()/1000
87 || !isCacheValid();
88 }
89
90 private boolean isOffline() {
91 try {
92 checkOfflineAccess();
93 return false;
94 } catch (OfflineAccessException e) {
95 return true;
96 }
97 }
98
99 protected void checkOfflineAccess() {
100 // To be overriden by subclasses
101 }
102
103 /**
104 * Updates data if required
105 * @return Returns the data
106 */
107 public byte[] updateIfRequired() throws T {
108 if (needsUpdate())
109 return updateForce();
110 return getData();
111 }
112
113 /**
114 * Updates data if required
115 * @return Returns the data as string
116 */
117 public String updateIfRequiredString() throws T {
118 if (needsUpdate())
119 return updateForceString();
120 return getDataString();
121 }
122
123 /**
124 * Executes an update regardless of updateInterval
125 * @return Returns the data
126 */
127 public byte[] updateForce() throws T {
128 this.data = updateData();
129 saveToDisk();
130 Main.pref.putInteger("cache." + ident, (int)(System.currentTimeMillis()/1000));
131 return data;
132 }
133
134 /**
135 * Executes an update regardless of updateInterval
136 * @return Returns the data as String
137 */
138 public String updateForceString() throws T {
139 updateForce();
140 return new String(data, StandardCharsets.UTF_8);
141 }
142
143 /**
144 * Returns the data without performing any updates
145 * @return the data
146 */
147 public byte[] getData() throws T {
148 if (data == null) {
149 loadFromDisk();
150 }
151 return data;
152 }
153
154 /**
155 * Returns the data without performing any updates
156 * @return the data as String
157 */
158 public String getDataString() throws T {
159 byte[] array = getData();
160 if (array == null) {
161 return null;
162 }
163 return new String(array, StandardCharsets.UTF_8);
164 }
165
166 /**
167 * Tries to load the data using the given ident from disk. If this fails, data will be updated, unless run in offline mode
168 */
169 private void loadFromDisk() throws T {
170 try (BufferedInputStream input = new BufferedInputStream(new FileInputStream(path))) {
171 this.data = new byte[input.available()];
172 input.read(this.data);
173 } catch (IOException e) {
174 if (!isOffline()) {
175 this.data = updateForce();
176 }
177 }
178 }
179
180 /**
181 * Stores the data to disk
182 */
183 private void saveToDisk() {
184 try (BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(path))) {
185 output.write(this.data);
186 output.flush();
187 } catch (IOException e) {
188 Main.error(e);
189 }
190 }
191
192 /**
193 * Flushes the data from memory. Class automatically reloads it from disk or updateData() if required
194 */
195 public void flushData() {
196 data = null;
197 }
198}
Note: See TracBrowser for help on using the repository browser.