~ubuntu-branches/ubuntu/saucy/gpsprune/saucy

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);
	}
}