1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
package tim.prune.gui.map;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* Class to control the reading and saving of map tiles
* to a cache on disk
*/
public class DiskTileCacher implements Runnable
{
/** URL to get image from */
private URL _url = null;
/** File to save image to */
private File _file = null;
/** Observer to be notified */
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
/**
* Private constructor
* @param inUrl URL to get
* @param inFile file to save to
*/
private DiskTileCacher(URL inUrl, File inFile, ImageObserver inObserver)
{
_url = inUrl;
_file = inFile;
_observer = inObserver;
new Thread(this).start();
}
/**
* Get the specified tile from the disk cache
* @param inBasePath base path to whole disk cache
* @param inTilePath relative path to requested tile
* @param inCheckAge true to check age of file, false to ignore
* @return tile image if available, or null if not there
*/
public static Image getTile(String inBasePath, String inTilePath, boolean inCheckAge)
{
if (inBasePath == null) {return null;}
File tileFile = new File(inBasePath, inTilePath);
Image image = null;
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) {}
}
}
return image;
}
/**
* Save the specified image tile to disk
* @param inUrl url to get image from
* @param inBasePath base path to disk cache
* @param inTilePath relative path to this tile
* @param inObserver observer to inform when load complete
*/
public static void saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver)
{
if (inBasePath == null || inTilePath == null) {return;}
// 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;
}
File tileFile = new File(basePath, inTilePath);
// Check if this file is already being loaded
if (!isBeingLoaded(tileFile))
{
File dir = tileFile.getParentFile();
// Start a new thread to load the image if necessary
if (dir.exists() || dir.mkdirs())
{
new DiskTileCacher(inUrl, tileFile, inObserver);
}
}
}
/**
* Check whether the given tile is already being loaded
* @param inFile desired file
* @return true if temporary file with this name exists
*/
private static boolean isBeingLoaded(File inFile)
{
File tempFile = new File(inFile.getAbsolutePath() + ".temp");
return tempFile.exists();
}
/**
* Run method for loading URL asynchronously and saving to file
*/
public void run()
{
boolean finished = false;
InputStream in = null;
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;}
try {
if (!tempFile.createNewFile()) {return;}
}
catch (Exception e) {return;}
}
try {
// Open streams from URL and to file
out = new FileOutputStream(tempFile);
in = _url.openStream();
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 (Exception e) {} // ignore
}
// Move temp file to desired file location
if (!tempFile.renameTo(_file)) {
// File couldn't be moved - delete both to be sure
tempFile.delete();
_file.delete();
}
// Tell parent that load is finished (parameters ignored)
_observer.imageUpdate(null, ImageObserver.ALLBITS, 0, 0, 0, 0);
}
}
|