source: osm/applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java@ 34784

Last change on this file since 34784 was 34784, checked in by donvip, 6 years ago

see #josm17116 - use existing translated string

  • Property svn:eol-style set to native
File size: 6.3 KB
Line 
1// License: GPL. For details, see Readme.txt file.
2package org.openstreetmap.gui.jmapviewer;
3
4import static org.openstreetmap.gui.jmapviewer.FeatureAdapter.tr;
5
6import java.io.IOException;
7import java.io.InputStream;
8import java.net.HttpURLConnection;
9import java.net.URL;
10import java.net.URLConnection;
11import java.util.HashMap;
12import java.util.Map;
13import java.util.Map.Entry;
14import java.util.concurrent.Executors;
15import java.util.concurrent.ThreadPoolExecutor;
16
17import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
18import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
19import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
20
21/**
22 * A {@link TileLoader} implementation that loads tiles from OSM.
23 *
24 * @author Jan Peter Stotz
25 */
26public class OsmTileLoader implements TileLoader {
27 private static final ThreadPoolExecutor jobDispatcher = (ThreadPoolExecutor) Executors.newFixedThreadPool(8);
28
29 private final class OsmTileJob implements TileJob {
30 private final Tile tile;
31 private InputStream input;
32 private boolean force;
33
34 private OsmTileJob(Tile tile) {
35 this.tile = tile;
36 }
37
38 @Override
39 public void run() {
40 synchronized (tile) {
41 if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
42 return;
43 tile.loaded = false;
44 tile.error = false;
45 tile.loading = true;
46 }
47 try {
48 URLConnection conn = loadTileFromOsm(tile);
49 if (force) {
50 conn.setUseCaches(false);
51 }
52 loadTileMetadata(tile, conn);
53 if ("no-tile".equals(tile.getValue("tile-info"))) {
54 tile.setError(tr("No tiles at this zoom level"));
55 } else {
56 input = conn.getInputStream();
57 try {
58 tile.loadImage(input);
59 } finally {
60 input.close();
61 input = null;
62 }
63 }
64 tile.setLoaded(true);
65 listener.tileLoadingFinished(tile, true);
66 } catch (IOException e) {
67 tile.setError(e.getMessage());
68 listener.tileLoadingFinished(tile, false);
69 if (input == null) {
70 try {
71 System.err.println("Failed loading " + tile.getUrl() +": "
72 +e.getClass() + ": " + e.getMessage());
73 } catch (IOException ioe) {
74 ioe.printStackTrace();
75 }
76 }
77 } finally {
78 tile.loading = false;
79 tile.setLoaded(true);
80 }
81 }
82
83 @Override
84 public void submit() {
85 submit(false);
86 }
87
88 @Override
89 public void submit(boolean force) {
90 this.force = force;
91 jobDispatcher.execute(this);
92 }
93 }
94
95 /**
96 * Holds the HTTP headers. Insert e.g. User-Agent here when default should not be used.
97 */
98 public Map<String, String> headers = new HashMap<>();
99
100 public int timeoutConnect;
101 public int timeoutRead;
102
103 protected TileLoaderListener listener;
104
105 public OsmTileLoader(TileLoaderListener listener) {
106 this(listener, null);
107 }
108
109 public OsmTileLoader(TileLoaderListener listener, Map<String, String> headers) {
110 this.headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*");
111 if (headers != null) {
112 this.headers.putAll(headers);
113 }
114 this.listener = listener;
115 }
116
117 @Override
118 public TileJob createTileLoaderJob(final Tile tile) {
119 return new OsmTileJob(tile);
120 }
121
122 protected URLConnection loadTileFromOsm(Tile tile) throws IOException {
123 URL url;
124 url = new URL(tile.getUrl());
125 URLConnection urlConn = url.openConnection();
126 if (urlConn instanceof HttpURLConnection) {
127 prepareHttpUrlConnection((HttpURLConnection) urlConn);
128 }
129 return urlConn;
130 }
131
132 protected void loadTileMetadata(Tile tile, URLConnection urlConn) {
133 String str = urlConn.getHeaderField("X-VE-TILEMETA-CaptureDatesRange");
134 if (str != null) {
135 tile.putValue("capture-date", str);
136 }
137 str = urlConn.getHeaderField("X-VE-Tile-Info");
138 if (str != null) {
139 tile.putValue("tile-info", str);
140 }
141
142 Long lng = urlConn.getExpiration();
143 if (lng.equals(0L)) {
144 try {
145 str = urlConn.getHeaderField("Cache-Control");
146 if (str != null) {
147 for (String token: str.split(",")) {
148 if (token.startsWith("max-age=")) {
149 lng = Long.parseLong(token.substring(8)) * 1000 +
150 System.currentTimeMillis();
151 }
152 }
153 }
154 } catch (NumberFormatException e) {
155 // ignore malformed Cache-Control headers
156 if (JMapViewer.debug) {
157 System.err.println(e.getMessage());
158 }
159 }
160 }
161 if (!lng.equals(0L)) {
162 tile.putValue("expires", lng.toString());
163 }
164 }
165
166 protected void prepareHttpUrlConnection(HttpURLConnection urlConn) {
167 for (Entry<String, String> e : headers.entrySet()) {
168 urlConn.setRequestProperty(e.getKey(), e.getValue());
169 }
170 if (timeoutConnect != 0)
171 urlConn.setConnectTimeout(timeoutConnect);
172 if (timeoutRead != 0)
173 urlConn.setReadTimeout(timeoutRead);
174 }
175
176 @Override
177 public String toString() {
178 return getClass().getSimpleName();
179 }
180
181 @Override
182 public boolean hasOutstandingTasks() {
183 return jobDispatcher.getTaskCount() > jobDispatcher.getCompletedTaskCount();
184 }
185
186 @Override
187 public void cancelOutstandingTasks() {
188 jobDispatcher.getQueue().clear();
189 }
190
191 /**
192 * Sets the maximum number of concurrent connections the tile loader will do
193 * @param num number of concurrent connections
194 */
195 public static void setConcurrentConnections(int num) {
196 jobDispatcher.setMaximumPoolSize(num);
197 }
198}
Note: See TracBrowser for help on using the repository browser.