1e590547f3842070e01d8758023a8a933102b6f1
1 package be
.nikiroo
.utils
;
4 import java
.io
.FileInputStream
;
5 import java
.io
.FileNotFoundException
;
6 import java
.io
.IOException
;
7 import java
.io
.InputStream
;
12 * A generic cache system, with special support for {@link URL}s.
14 * This cache also manages timeout information.
20 private long tooOldChanging
;
21 private long tooOldStable
;
24 * Create a new {@link Cache} object.
27 * the directory to use as cache
28 * @param hoursChanging
29 * the number of hours after which a cached file that is thought
30 * to change ~often is considered too old (or -1 for
33 * the number of hours after which a cached file that is thought
34 * to change rarely is considered too old (or -1 for
38 * in case of I/O error
40 public Cache(File dir
, int hoursChanging
, int hoursStable
)
43 this.tooOldChanging
= 1000 * 60 * 60 * hoursChanging
;
44 this.tooOldStable
= 1000 * 60 * 60 * hoursStable
;
46 if (dir
!= null && !dir
.exists()) {
50 if (dir
== null || !dir
.exists()) {
51 throw new IOException("Cannot create the cache directory: "
52 + (dir
== null ?
"null" : dir
.getAbsolutePath()));
57 * Check the resource to see if it is in the cache.
60 * the resource to check
62 * allow files even if they are considered too old
64 * a stable file (that dones't change too often) -- parameter
65 * used to check if the file is too old to keep or not
67 * @return TRUE if it is
70 public boolean check(URL url
, boolean allowTooOld
, boolean stable
) {
71 File file
= getCached(url
);
73 if (allowTooOld
|| !isOld(file
, stable
)) {
82 * Clean the cache (delete the cached items).
85 * only clean the files that are considered too old for a stable
88 * @return the number of cleaned items
90 public int clean(boolean onlyOld
) {
91 return clean(onlyOld
, dir
);
95 * Trace information (info/error) generated by this class.
97 * You can override it if you don't want the default sysout/syserr.
102 * TRUE for error messages, FALSE for information messages
104 protected void trace(String message
, boolean error
) {
106 System
.err
.println(message
);
108 System
.out
.println(message
);
113 * Clean the cache (delete the cached items) in the given cache directory.
116 * only clean the files that are considered too old for stable
119 * the cache directory to clean
121 * @return the number of cleaned items
123 private int clean(boolean onlyOld
, File cacheDir
) {
125 for (File file
: cacheDir
.listFiles()) {
126 if (file
.isDirectory()) {
127 num
+= clean(onlyOld
, file
);
129 if (!onlyOld
|| isOld(file
, true)) {
133 trace("Cannot delete temporary file: "
134 + file
.getAbsolutePath(), true);
144 * Open a resource from the cache if it exists.
149 * allow files even if they are considered too old
151 * a stable file (that dones't change too often) -- parameter
152 * used to check if the file is too old to keep or not
154 * @return the opened resource if found, NULL if not
156 public InputStream
load(String uniqueID
, boolean allowTooOld
, boolean stable
) {
157 return load(getCached(uniqueID
), allowTooOld
, stable
);
161 * Open a resource from the cache if it exists.
164 * the resource to open
166 * allow files even if they are considered too old
168 * a stable file (that dones't change too often) -- parameter
169 * used to check if the file is too old to keep or not
171 * @return the opened resource if found, NULL if not
173 public InputStream
load(URL url
, boolean allowTooOld
, boolean stable
) {
174 return load(getCached(url
), allowTooOld
, stable
);
178 * Open a resource from the cache if it exists.
181 * the resource to open
183 * allow files even if they are considered too old
185 * a stable file (that dones't change too often) -- parameter
186 * used to check if the file is too old to keep or not
188 * @return the opened resource if found, NULL if not
190 private InputStream
load(File cached
, boolean allowTooOld
, boolean stable
) {
191 if (cached
.exists() && (allowTooOld
|| !isOld(cached
, stable
))) {
193 return new MarkableFileInputStream(new FileInputStream(cached
));
194 } catch (FileNotFoundException e
) {
203 * Save the given resource to the cache.
208 * a unique ID used to locate the cached resource
210 * @return the resulting {@link File}
212 * @throws IOException
213 * in case of I/O error
215 public File
save(InputStream in
, String uniqueID
) throws IOException
{
216 File cached
= getCached(uniqueID
);
217 cached
.getParentFile().mkdirs();
218 return save(in
, cached
);
222 * Save the given resource to the cache.
227 * the {@link URL} used to locate the cached resource
229 * @return the actual cache file
231 * @throws IOException
232 * in case of I/O error
234 public File
save(InputStream in
, URL url
) throws IOException
{
235 File cached
= getCached(url
);
236 return save(in
, cached
);
240 * Save the given resource to the cache.
245 * the cached {@link File} to save to
247 * @return the actual cache file
249 * @throws IOException
250 * in case of I/O error
252 private File
save(InputStream in
, File cached
) throws IOException
{
253 IOUtils
.write(in
, cached
);
258 * Remove the given resource from the cache.
261 * a unique ID used to locate the cached resource
263 * @return TRUE if it was removed
265 public boolean remove(String uniqueID
) {
266 File cached
= getCached(uniqueID
);
267 return cached
.delete();
271 * Remove the given resource from the cache.
274 * the {@link URL} used to locate the cached resource
276 * @return TRUE if it was removed
278 public boolean remove(URL url
) {
279 File cached
= getCached(url
);
280 return cached
.delete();
284 * Check if the {@link File} is too old according to
285 * {@link Cache#tooOldChanging}.
290 * TRUE to denote stable files, that are not supposed to change
293 * @return TRUE if it is
295 private boolean isOld(File file
, boolean stable
) {
296 long max
= tooOldChanging
;
305 long time
= new Date().getTime() - file
.lastModified();
307 trace("Timestamp in the future for file: " + file
.getAbsolutePath(),
311 return time
< 0 || time
> max
;
315 * Return the associated cache {@link File} from this {@link URL}.
320 * @return the cached {@link File} version of this {@link URL}
322 private File
getCached(URL url
) {
325 String name
= url
.getHost();
326 if (name
== null || name
.isEmpty()) {
328 File file
= new File(url
.getFile());
329 subdir
= new File(file
.getParent().replace("..", "__"));
330 subdir
= new File(dir
, allowedChars(subdir
.getPath()));
331 name
= allowedChars(url
.getFile());
334 File subsubDir
= new File(dir
, allowedChars(url
.getHost()));
335 subdir
= new File(subsubDir
, "_" + allowedChars(url
.getPath()));
336 name
= allowedChars("_" + url
.getQuery());
339 File cacheFile
= new File(subdir
, name
);
346 * Get the basic cache resource file corresponding to this unique ID.
348 * Note that you may need to add a sub-directory in some cases.
353 * @return the cached version if present, NULL if not
355 private File
getCached(String uniqueID
) {
356 File file
= new File(dir
, allowedChars(uniqueID
));
357 File subdir
= new File(file
.getParentFile(), "_");
358 return new File(subdir
, file
.getName());
362 * Replace not allowed chars (in a {@link File}) by "_".
365 * the raw {@link String}
367 * @return the sanitised {@link String}
369 private String
allowedChars(String raw
) {
370 return raw
.replace('/', '_').replace(':', '_').replace("\\", "_");