X-Git-Url: https://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fgui%2Fmap%2FDiskTileCacher.java;h=459b140f2c0108b9adf35805bf1b0451d3f80811;hb=326f489e36aa7f235bc19409a57bf4955cd50f24;hp=dfc4f927aed2aee0baef04623c37831e824a5156;hpb=c0387c124840c9407e040600fda88f3c3e8f6aa6;p=GpsPrune.git diff --git a/tim/prune/gui/map/DiskTileCacher.java b/tim/prune/gui/map/DiskTileCacher.java index dfc4f92..459b140 100644 --- a/tim/prune/gui/map/DiskTileCacher.java +++ b/tim/prune/gui/map/DiskTileCacher.java @@ -8,6 +8,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.net.URLConnection; +import java.util.HashSet; + +import tim.prune.GpsPrune; /** * Class to control the reading and saving of map tiles @@ -23,6 +27,8 @@ public class DiskTileCacher implements Runnable private ImageObserver _observer = null; /** Time limit to cache images for */ private static final long CACHE_TIME_LIMIT = 20 * 24 * 60 * 60 * 1000; // 20 days in ms + /** Hashset of all blocked / 404 tiles to avoid requesting them again */ + private static final HashSet BLOCKED_URLS = new HashSet(); /** * Private constructor @@ -49,14 +55,17 @@ public class DiskTileCacher implements Runnable if (inBasePath == null) {return null;} File tileFile = new File(inBasePath, inTilePath); Image image = null; - if (tileFile.exists() && tileFile.canRead() && tileFile.length() > 0) { + if (tileFile.exists() && tileFile.canRead() && tileFile.length() > 0) + { long fileStamp = tileFile.lastModified(); if (!inCheckAge || ((System.currentTimeMillis()-fileStamp) < CACHE_TIME_LIMIT)) { try { image = Toolkit.getDefaultToolkit().createImage(tileFile.getAbsolutePath()); } - catch (Exception e) {} + catch (Exception e) { + System.err.println("createImage: " + e.getClass().getName() + " _ " + e.getMessage()); + } } } return image; @@ -68,28 +77,31 @@ public class DiskTileCacher implements Runnable * @param inBasePath base path to disk cache * @param inTilePath relative path to this tile * @param inObserver observer to inform when load complete + * @return true if successful, false for failure */ - public static void saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver) + public static boolean saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver) { - if (inBasePath == null || inTilePath == null) {return;} + if (inBasePath == null || inTilePath == null) {return false;} // save file if possible File basePath = new File(inBasePath); if (!basePath.exists() || !basePath.isDirectory() || !basePath.canWrite()) { - //System.err.println("Can't write"); // Can't write to base path - return; + return false; } File tileFile = new File(basePath, inTilePath); // Check if this file is already being loaded - if (!isBeingLoaded(tileFile)) + if (isBeingLoaded(tileFile)) {return true;} + // Check if it has already failed + if (BLOCKED_URLS.contains(inUrl.toString())) {return true;} + + File dir = tileFile.getParentFile(); + // Start a new thread to load the image if necessary + if ((dir.exists() || dir.mkdirs()) && dir.canWrite()) { - File dir = tileFile.getParentFile(); - // Start a new thread to load the image if necessary - if (dir.exists() || dir.mkdirs()) - { - new DiskTileCacher(inUrl, tileFile, inObserver); - } + new DiskTileCacher(inUrl, tileFile, inObserver); + return true; } + return false; // couldn't write the file } /** @@ -100,7 +112,12 @@ public class DiskTileCacher implements Runnable private static boolean isBeingLoaded(File inFile) { File tempFile = new File(inFile.getAbsolutePath() + ".temp"); - return tempFile.exists(); + if (!tempFile.exists()) { + return false; + } + // File exists, so check if it was created recently + final long fileAge = System.currentTimeMillis() - tempFile.lastModified(); + return fileAge < 1000000L; // overwrite if the temp file is still there after 1000s } /** @@ -113,34 +130,44 @@ public class DiskTileCacher implements Runnable FileOutputStream out = null; File tempFile = new File(_file.getAbsolutePath() + ".temp"); // Use a synchronized block across all threads to make sure this url is only fetched once - synchronized (DiskTileCacher.class) { - if (tempFile.exists()) {return;} + synchronized (DiskTileCacher.class) + { + if (tempFile.exists()) {tempFile.delete();} try { if (!tempFile.createNewFile()) {return;} } catch (Exception e) {return;} } - try { + try + { // Open streams from URL and to file out = new FileOutputStream(tempFile); - in = _url.openStream(); + // Set http user agent on connection + URLConnection conn = _url.openConnection(); + conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER); + in = conn.getInputStream(); int d = 0; // Loop over each byte in the stream (maybe buffering is more efficient?) while ((d = in.read()) >= 0) { out.write(d); } finished = true; - } catch (IOException e) {} - finally { - try { - in.close(); - out.close(); - if (!finished) {tempFile.delete();} + } catch (IOException e) { + System.err.println("ioe: " + e.getClass().getName() + " - " + e.getMessage()); + BLOCKED_URLS.add(_url.toString()); + } + finally + { + // clean up files + try {in.close();} catch (Exception e) {} // ignore + try {out.close();} catch (Exception e) {} // ignore + if (!finished) { + tempFile.delete(); } - catch (Exception e) {} // ignore } // Move temp file to desired file location - if (!tempFile.renameTo(_file)) { + if (!tempFile.renameTo(_file)) + { // File couldn't be moved - delete both to be sure tempFile.delete(); _file.delete();