1 package tim.prune.gui.map;
4 import java.awt.Toolkit;
5 import java.awt.image.ImageObserver;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
9 import java.io.InputStream;
13 * Class to control the reading and saving of map tiles
16 public class DiskTileCacher implements Runnable
18 /** URL to get image from */
19 private URL _url = null;
20 /** File to save image to */
21 private File _file = null;
22 /** Observer to be notified */
23 private ImageObserver _observer = null;
24 /** Time limit to cache images for */
25 private static final long CACHE_TIME_LIMIT = 20 * 24 * 60 * 60 * 1000; // 20 days in ms
29 * @param inUrl URL to get
30 * @param inFile file to save to
32 private DiskTileCacher(URL inUrl, File inFile, ImageObserver inObserver)
36 _observer = inObserver;
37 new Thread(this).start();
41 * Get the specified tile from the disk cache
42 * @param inBasePath base path to whole disk cache
43 * @param inTilePath relative path to requested tile
44 * @param inCheckAge true to check age of file, false to ignore
45 * @return tile image if available, or null if not there
47 public static Image getTile(String inBasePath, String inTilePath, boolean inCheckAge)
49 if (inBasePath == null) {return null;}
50 File tileFile = new File(inBasePath, inTilePath);
52 if (tileFile.exists() && tileFile.canRead() && tileFile.length() > 0) {
53 long fileStamp = tileFile.lastModified();
54 if (!inCheckAge || ((System.currentTimeMillis()-fileStamp) < CACHE_TIME_LIMIT))
57 image = Toolkit.getDefaultToolkit().createImage(tileFile.getAbsolutePath());
59 catch (Exception e) {}
66 * Save the specified image tile to disk
67 * @param inUrl url to get image from
68 * @param inBasePath base path to disk cache
69 * @param inTilePath relative path to this tile
70 * @param inObserver observer to inform when load complete
71 * @return true if successful, false for failure
73 public static boolean saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver)
75 // TODO: Check that these are getting blocked properly
76 if (inBasePath == null || inTilePath == null) {return false;}
77 // save file if possible
78 File basePath = new File(inBasePath);
79 if (!basePath.exists() || !basePath.isDirectory() || !basePath.canWrite()) {
80 // Can't write to base path
83 File tileFile = new File(basePath, inTilePath);
84 // Check if this file is already being loaded
85 if (isBeingLoaded(tileFile)) {return true;}
87 File dir = tileFile.getParentFile();
88 // Start a new thread to load the image if necessary
89 if ((dir.exists() || dir.mkdirs()) && dir.canWrite())
91 new DiskTileCacher(inUrl, tileFile, inObserver);
94 return false; // couldn't write the file
98 * Check whether the given tile is already being loaded
99 * @param inFile desired file
100 * @return true if temporary file with this name exists
102 private static boolean isBeingLoaded(File inFile)
104 File tempFile = new File(inFile.getAbsolutePath() + ".temp");
105 return tempFile.exists();
109 * Run method for loading URL asynchronously and saving to file
113 boolean finished = false;
114 InputStream in = null;
115 FileOutputStream out = null;
116 File tempFile = new File(_file.getAbsolutePath() + ".temp");
117 // Use a synchronized block across all threads to make sure this url is only fetched once
118 synchronized (DiskTileCacher.class) {
119 if (tempFile.exists()) {return;}
121 if (!tempFile.createNewFile()) {return;}
123 catch (Exception e) {return;}
127 // Open streams from URL and to file
128 out = new FileOutputStream(tempFile);
129 in = _url.openStream();
131 // Loop over each byte in the stream (maybe buffering is more efficient?)
132 while ((d = in.read()) >= 0) {
136 } catch (IOException e) {}
140 try {in.close();} catch (Exception e) {} // ignore
141 try {out.close();} catch (Exception e) {} // ignore
146 // Move temp file to desired file location
147 if (!tempFile.renameTo(_file))
149 // File couldn't be moved - delete both to be sure
153 // Tell parent that load is finished (parameters ignored)
154 _observer.imageUpdate(null, ImageObserver.ALLBITS, 0, 0, 0, 0);