X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FCache.java;h=18b811e397f09c241af4ebaef49a2a1662c4c8a0;hb=2e465ed3dc72efcdf96e419b39d6119c0cc41c6c;hp=dcbde74ea4b053ae512c7ed9149114af5f4aa77e;hpb=530d4062471346d6ececf76d74a0358c91323998;p=nikiroo-utils.git diff --git a/src/be/nikiroo/utils/Cache.java b/src/be/nikiroo/utils/Cache.java index dcbde74..6233082 100644 --- a/src/be/nikiroo/utils/Cache.java +++ b/src/be/nikiroo/utils/Cache.java @@ -1,13 +1,14 @@ package be.nikiroo.utils; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Date; +import be.nikiroo.utils.streams.MarkableFileInputStream; + /** * A generic cache system, with special support for {@link URL}s. *
@@ -21,6 +22,12 @@ public class Cache { private long tooOldStable; private TraceHandler tracer = new TraceHandler(); + /** + * Only for inheritance. + */ + protected Cache() { + } + /** * Create a new {@link Cache} object. * @@ -41,8 +48,8 @@ public class Cache { public Cache(File dir, int hoursChanging, int hoursStable) throws IOException { this.dir = dir; - this.tooOldChanging = 1000 * 60 * 60 * hoursChanging; - this.tooOldStable = 1000 * 60 * 60 * hoursStable; + this.tooOldChanging = 1000L * 60 * 60 * hoursChanging; + this.tooOldStable = 1000L * 60 * 60 * hoursStable; if (dir != null && !dir.exists()) { dir.mkdirs(); @@ -70,9 +77,31 @@ public class Cache { * the new traces handler */ public void setTraceHandler(TraceHandler tracer) { + if (tracer == null) { + tracer = new TraceHandler(false, false, false); + } + this.tracer = tracer; } + /** + * Check the resource to see if it is in the cache. + * + * @param uniqueID + * the resource to check + * @param allowTooOld + * allow files even if they are considered too old + * @param stable + * a stable file (that dones't change too often) -- parameter + * used to check if the file is too old to keep or not + * + * @return TRUE if it is + * + */ + public boolean check(String uniqueID, boolean allowTooOld, boolean stable) { + return check(getCached(uniqueID), allowTooOld, stable); + } + /** * Check the resource to see if it is in the cache. * @@ -88,9 +117,31 @@ public class Cache { * */ public boolean check(URL url, boolean allowTooOld, boolean stable) { - File file = getCached(url); - if (file.exists()) { - if (allowTooOld || !isOld(file, stable)) { + return check(getCached(url), allowTooOld, stable); + } + + /** + * Check the resource to see if it is in the cache. + * + * @param cached + * the resource to check + * @param allowTooOld + * allow files even if they are considered too old + * @param stable + * a stable file (that dones't change too often) -- parameter + * used to check if the file is too old to keep or not + * + * @return TRUE if it is + * + */ + private boolean check(File cached, boolean allowTooOld, boolean stable) { + if (cached.exists() && cached.isFile()) { + if (!allowTooOld && isOld(cached, stable)) { + if (!cached.delete()) { + tracer.error("Cannot delete temporary file: " + + cached.getAbsolutePath()); + } + } else { return true; } } @@ -108,7 +159,16 @@ public class Cache { * @return the number of cleaned items */ public int clean(boolean onlyOld) { - return clean(onlyOld, dir); + long ms = System.currentTimeMillis(); + + tracer.trace("Cleaning cache from old files..."); + + int num = clean(onlyOld, dir, -1); + + tracer.trace(num + "cache items cleaned in " + + (System.currentTimeMillis() - ms) + " ms"); + + return num; } /** @@ -119,21 +179,31 @@ public class Cache { * resources * @param cacheDir * the cache directory to clean + * @param limit + * stop after limit files deleted, or -1 for unlimited * * @return the number of cleaned items */ - private int clean(boolean onlyOld, File cacheDir) { + private int clean(boolean onlyOld, File cacheDir, int limit) { int num = 0; - for (File file : cacheDir.listFiles()) { - if (file.isDirectory()) { - num += clean(onlyOld, file); - } else { - if (!onlyOld || isOld(file, true)) { - if (file.delete()) { - num++; - } else { - tracer.error("Cannot delete temporary file: " - + file.getAbsolutePath()); + File[] files = cacheDir.listFiles(); + if (files != null) { + for (File file : files) { + if (limit >= 0 && num >= limit) { + return num; + } + + if (file.isDirectory()) { + num += clean(onlyOld, file, limit); + file.delete(); // only if empty + } else { + if (!onlyOld || isOld(file, true)) { + if (file.delete()) { + num++; + } else { + tracer.error("Cannot delete temporary file: " + + file.getAbsolutePath()); + } } } } @@ -167,8 +237,9 @@ public class Cache { * @param allowTooOld * allow files even if they are considered too old * @param stable - * a stable file (that dones't change too often) -- parameter - * used to check if the file is too old to keep or not + * a stable file (that doesn't change too often) -- parameter + * used to check if the file is too old to keep or not in the + * cache * * @return the opened resource if found, NULL if not */ @@ -190,9 +261,10 @@ public class Cache { * @return the opened resource if found, NULL if not */ private InputStream load(File cached, boolean allowTooOld, boolean stable) { - if (cached.exists() && (allowTooOld || !isOld(cached, stable))) { + if (cached.exists() && cached.isFile() + && (allowTooOld || !isOld(cached, stable))) { try { - return new MarkableFileInputStream(new FileInputStream(cached)); + return new MarkableFileInputStream(cached); } catch (FileNotFoundException e) { return null; } @@ -209,12 +281,12 @@ public class Cache { * @param uniqueID * a unique ID used to locate the cached resource * - * @return the resulting {@link File} + * @return the number of bytes written * * @throws IOException * in case of I/O error */ - public File save(InputStream in, String uniqueID) throws IOException { + public long save(InputStream in, String uniqueID) throws IOException { File cached = getCached(uniqueID); cached.getParentFile().mkdirs(); return save(in, cached); @@ -228,32 +300,39 @@ public class Cache { * @param url * the {@link URL} used to locate the cached resource * - * @return the actual cache file + * @return the number of bytes written * * @throws IOException * in case of I/O error */ - public File save(InputStream in, URL url) throws IOException { + public long save(InputStream in, URL url) throws IOException { File cached = getCached(url); return save(in, cached); } /** * Save the given resource to the cache. + *
+ * Will also clean the {@link Cache} from old files. * * @param in * the input data * @param cached * the cached {@link File} to save to * - * @return the actual cache file + * @return the number of bytes written * * @throws IOException * in case of I/O error */ - private File save(InputStream in, File cached) throws IOException { - IOUtils.write(in, cached); - return cached; + private long save(InputStream in, File cached) throws IOException { + // We want to force at least an immediate SAVE/LOAD to work for some + // workflows, even if we don't accept cached files (times set to "0" + // -- and not "-1" or a positive value) + clean(true, dir, 10); + cached.getParentFile().mkdirs(); // in case we deleted our own parent + long bytes = IOUtils.write(in, cached); + return bytes; } /** @@ -328,7 +407,11 @@ public class Cache { if (name == null || name.isEmpty()) { // File File file = new File(url.getFile()); - subdir = new File(file.getParent().replace("..", "__")); + if (file.getParent() == null) { + subdir = new File("+"); + } else { + subdir = new File(file.getParent().replace("..", "__")); + } subdir = new File(dir, allowedChars(subdir.getPath())); name = allowedChars(url.getFile()); } else {