import java.awt.image.*;
import java.awt.*;
import java.io.*;
-import java.net.URL;
-import java.net.URLConnection;
-
-
-class AltosCacheImage {
- Component component;
- File file;
- VolatileImage image;
- int width;
- int height;
- long used;
-
- public void load_image() throws IOException {
- BufferedImage bimg = ImageIO.read(file);
- Graphics2D g = image.createGraphics();
- g.drawImage(bimg, 0, 0, null);
- bimg.flush();
+import java.net.*;
+
+public class AltosSiteMapCache {
+ static final long google_maps_ratelimit_ms = 1200;
+ // Google limits static map queries to 50 per minute per IP, so
+ // each query should take at least 1.2 seconds.
+
+ static final int success = 0;
+ static final int loading = 1;
+ static final int failed = 2;
+ static final int bad_request = 3;
+ static final int forbidden = 4;
+
+ public static boolean has_map(File file, String url) {
+ return file.exists();
}
- public Image validate() {
- int returnCode;
+ static long forbidden_time;
+ static boolean forbidden_set = false;
+ static final long forbidden_interval = 60l * 1000l * 1000l * 1000l;
+
+ static private Object fetch_lock = new Object();
+
+ public static int fetch_map(File file, String url) {
+ if (file.exists())
+ return success;
+
+ if (forbidden_set && (System.nanoTime() - forbidden_time) < forbidden_interval)
+ return forbidden;
+
+ synchronized (fetch_lock) {
+ URL u;
+ long startTime = System.nanoTime();
+
+ try {
+ u = new URL(url);
+ } catch (java.net.MalformedURLException e) {
+ return bad_request;
+ }
- if (image != null)
- returnCode = image.validate(component.getGraphicsConfiguration());
- else
- returnCode = VolatileImage.IMAGE_INCOMPATIBLE;
- if (returnCode == VolatileImage.IMAGE_RESTORED) {
+ byte[] data;
+ URLConnection uc = null;
try {
- load_image();
+ uc = u.openConnection();
+ String type = uc.getContentType();
+ int contentLength = uc.getContentLength();
+ if (uc instanceof HttpURLConnection) {
+ int response = ((HttpURLConnection) uc).getResponseCode();
+ switch (response) {
+ case HttpURLConnection.HTTP_FORBIDDEN:
+ case HttpURLConnection.HTTP_PAYMENT_REQUIRED:
+ case HttpURLConnection.HTTP_UNAUTHORIZED:
+ forbidden_time = System.nanoTime();
+ forbidden_set = true;
+ return forbidden;
+ }
+ }
+ InputStream in = new BufferedInputStream(uc.getInputStream());
+ int bytesRead = 0;
+ int offset = 0;
+ data = new byte[contentLength];
+ while (offset < contentLength) {
+ bytesRead = in.read(data, offset, data.length - offset);
+ if (bytesRead == -1)
+ break;
+ offset += bytesRead;
+ }
+ in.close();
+
+ if (offset != contentLength)
+ return failed;
+
} catch (IOException e) {
- return null;
+ return failed;
}
- } else if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) {
- image = component.createVolatileImage(width, height);
+
try {
- load_image();
+ FileOutputStream out = new FileOutputStream(file);
+ out.write(data);
+ out.flush();
+ out.close();
+ } catch (FileNotFoundException e) {
+ return bad_request;
} catch (IOException e) {
- return null;
+ if (file.exists())
+ file.delete();
+ return bad_request;
}
- }
- return image;
- }
- public void flush() {
- image.flush();
+ long duration_ms = (System.nanoTime() - startTime) / 1000000;
+ if (duration_ms < google_maps_ratelimit_ms) {
+ try {
+ Thread.sleep(google_maps_ratelimit_ms - duration_ms);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ return success;
+ }
}
- public AltosCacheImage(Component component, File file, int w, int h) throws IOException {
- this.component = component;
- this.file = file;
- width = w;
- height = h;
- image = component.createVolatileImage(w, h);
- used = 0;
- }
-}
+ static final int min_cache_size = 9;
+ static final int max_cache_size = 24;
-public class AltosSiteMapCache extends JLabel {
- static final long google_maps_ratelimit_ms = 1200;
- // Google limits static map queries to 50 per minute per IP, so
- // each query should take at least 1.2 seconds.
+ static int cache_size = min_cache_size;
- public static boolean fetchMap(File file, String url) {
- if (file.exists())
- return true;
+ static AltosSiteMapImage[] images = new AltosSiteMapImage[cache_size];
- URL u;
- long startTime = System.nanoTime();
+ static Object cache_lock = new Object();
- try {
- u = new URL(url);
- } catch (java.net.MalformedURLException e) {
- return false;
- }
+ public static void set_cache_size(int new_size) {
+ if (new_size < min_cache_size)
+ new_size = min_cache_size;
+ if (new_size > max_cache_size)
+ new_size = max_cache_size;
+ if (new_size == cache_size)
+ return;
- byte[] data;
- try {
- URLConnection uc = u.openConnection();
- int contentLength = uc.getContentLength();
- InputStream in = new BufferedInputStream(uc.getInputStream());
- int bytesRead = 0;
- int offset = 0;
- data = new byte[contentLength];
- while (offset < contentLength) {
- bytesRead = in.read(data, offset, data.length - offset);
- if (bytesRead == -1)
- break;
- offset += bytesRead;
- }
- in.close();
+ synchronized(cache_lock) {
+ AltosSiteMapImage[] new_images = new AltosSiteMapImage[new_size];
- if (offset != contentLength) {
- return false;
+ for (int i = 0; i < cache_size; i++) {
+ if (i < new_size)
+ new_images[i] = images[i];
+ else
+ images[i].flush();
}
- } catch (IOException e) {
- return false;
+ images = new_images;
+ cache_size = new_size;
}
+ }
- try {
- FileOutputStream out = new FileOutputStream(file);
- out.write(data);
- out.flush();
- out.close();
- } catch (FileNotFoundException e) {
- return false;
- } catch (IOException e) {
- if (file.exists()) {
- file.delete();
- }
- return false;
- }
+ static long used;
- long duration_ms = (System.nanoTime() - startTime) / 1000000;
- if (duration_ms < google_maps_ratelimit_ms) {
- try {
- Thread.sleep(google_maps_ratelimit_ms - duration_ms);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
+ private static Point tile_loc(AltosSiteMapTile tile) {
+ Rectangle r = tile.getBounds();
+ int x = r.x / 512;
+ int y = r.y / 512;
- return true;
+ return new Point (x, y);
}
- static int cache_size = 9;
+ private static void dump_cache() {
+ int min_x = 1000, max_x = -1000, min_y = 1000, max_y = -1000;
- static AltosCacheImage[] images;
+ for (int i = 0; i < cache_size; i++) {
+ AltosSiteMapImage image = images[i];
+ if (image != null) {
+ Point p = tile_loc(image.tile);
+ min_x = min_x < p.x ? min_x : p.x;
+ max_x = max_x > p.x ? max_x : p.x;
+ min_y = min_y < p.y ? min_y : p.y;
+ max_y = max_y > p.y ? max_y : p.y;
+ System.out.printf ("entry %d %d,%d used %d\n", i, p.x, p.y, image.used);
+ } else {
+ System.out.printf ("entry %d empty\n", i);
+ }
+ }
- static long used;
+ int[][] map = new int[max_x - min_x + 1][max_y - min_y + 1];
+ for (int i = 0; i < cache_size; i++) {
+ AltosSiteMapImage image = images[i];
+ if (image != null) {
+ Point p = tile_loc(image.tile);
+ map[p.x - min_x][p.y - min_y]++;
+ }
+ }
- public static void set_cache_size(int cache_size) {
- AltosSiteMapCache.cache_size = cache_size;
- images = null;
+ for (int y = min_y; y <= max_y; y++) {
+ for (int x = min_x; x <= max_x; x++)
+ System.out.printf (" %2d", map[x - min_x][y - min_y]);
+ System.out.printf("\n");
+ }
}
- public static Image get_image(Component component, File file, int width, int height) {
+ public static AltosSiteMapImage get_image(AltosSiteMapTile tile, File file, int width, int height) {
int oldest = -1;
long age = used;
- AltosCacheImage image;
- if (images == null)
- images = new AltosCacheImage[cache_size];
- for (int i = 0; i < cache_size; i++) {
- image = images[i];
- if (image == null) {
- oldest = i;
- break;
+ synchronized(cache_lock) {
+ AltosSiteMapImage image = null;
+ for (int i = 0; i < cache_size; i++) {
+ image = images[i];
+
+ if (image == null) {
+ oldest = i;
+ break;
+ }
+ if (image.tile == tile && file.equals(image.file)) {
+ image.used = used++;
+ return image;
+ }
+ if (image.used < age) {
+ oldest = i;
+ age = image.used;
+ }
}
- if (image.component == component && file.equals(image.file)) {
+
+ try {
+ image = new AltosSiteMapImage(tile, file, width, height);
image.used = used++;
- return image.validate();
- }
- if (image.used < age) {
- oldest = i;
- age = image.used;
+ if (images[oldest] != null) {
+// dump_cache();
+ AltosSiteMap.debug_component(images[oldest].tile, "replacing cache");
+ AltosSiteMap.debug_component(tile, "replaced cache");
+ images[oldest].flush();
+ }
+ images[oldest] = image;
+ return image;
+ } catch (IOException e) {
+ return null;
}
}
-
- try {
- image = new AltosCacheImage(component, file, width, height);
- image.used = used++;
- if (images[oldest] != null)
- images[oldest].flush();
- images[oldest] = image;
- return image.validate();
- } catch (IOException e) {
- return null;
- }
}
}