2 * Copyright © 2014 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18 package org.altusmetrum.altoslib_7;
24 public class AltosMapStore {
27 LinkedList<AltosMapStoreListener> listeners = new LinkedList<AltosMapStoreListener>();
35 public synchronized void add_listener(AltosMapStoreListener listener) {
36 if (!listeners.contains(listener))
37 listeners.add(listener);
40 public synchronized void remove_listener(AltosMapStoreListener listener) {
41 listeners.remove(listener);
44 private synchronized void notify_listeners(int status) {
46 for (AltosMapStoreListener listener : listeners)
47 listener.notify_store(this, status);
50 static Object forbidden_lock = new Object();
51 static long forbidden_time;
52 static boolean forbidden_set;
54 private int fetch_url() {
59 } catch (java.net.MalformedURLException e) {
60 return AltosMapTile.bad_request;
64 URLConnection uc = null;
66 uc = u.openConnection();
67 String type = uc.getContentType();
68 int contentLength = uc.getContentLength();
69 if (uc instanceof HttpURLConnection) {
70 int response = ((HttpURLConnection) uc).getResponseCode();
72 case HttpURLConnection.HTTP_FORBIDDEN:
73 case HttpURLConnection.HTTP_PAYMENT_REQUIRED:
74 case HttpURLConnection.HTTP_UNAUTHORIZED:
75 synchronized (forbidden_lock) {
76 forbidden_time = System.nanoTime();
78 return AltosMapTile.forbidden;
82 InputStream in = new BufferedInputStream(uc.getInputStream());
85 data = new byte[contentLength];
86 while (offset < contentLength) {
87 bytesRead = in.read(data, offset, data.length - offset);
94 if (offset != contentLength)
95 return AltosMapTile.failed;
97 } catch (IOException e) {
98 return AltosMapTile.failed;
102 FileOutputStream out = new FileOutputStream(file);
106 } catch (FileNotFoundException e) {
107 return AltosMapTile.bad_request;
108 } catch (IOException e) {
111 return AltosMapTile.bad_request;
113 return AltosMapTile.success;
116 static Object fetch_lock = new Object();
118 static final long forbidden_interval = 60l * 1000l * 1000l * 1000l;
119 static final long google_maps_ratelimit_ms = 1200;
121 class loader implements Runnable {
125 notify_listeners(AltosMapTile.success);
129 synchronized(forbidden_lock) {
130 if (forbidden_set && (System.nanoTime() - forbidden_time) < forbidden_interval) {
131 notify_listeners(AltosMapTile.forbidden);
138 if (!AltosVersion.has_google_maps_api_key()) {
139 synchronized (fetch_lock) {
140 long startTime = System.nanoTime();
141 new_status = fetch_url();
142 if (new_status == AltosMapTile.success) {
143 long duration_ms = (System.nanoTime() - startTime) / 1000000;
144 if (duration_ms < google_maps_ratelimit_ms) {
146 Thread.sleep(google_maps_ratelimit_ms - duration_ms);
147 } catch (InterruptedException e) {
148 Thread.currentThread().interrupt();
154 new_status = fetch_url();
156 notify_listeners(new_status);
160 private void load() {
161 loader l = new loader();
162 Thread lt = new Thread(l);
166 private AltosMapStore (String url, File file) {
171 status = AltosMapTile.success;
173 status = AltosMapTile.loading;
178 public boolean equals(AltosMapStore other) {
179 return url.equals(other.url);
182 static HashMap<String,AltosMapStore> stores = new HashMap<String,AltosMapStore>();
184 public static AltosMapStore get(String url, File file) {
186 synchronized(stores) {
187 if (stores.containsKey(url)) {
188 store = stores.get(url);
190 store = new AltosMapStore(url, file);
191 stores.put(url, store);