001 package org.openstreetmap.gui.jmapviewer;
002
003 //License: GPL. Copyright 2008 by Jan Peter Stotz
004
005 import java.io.IOException;
006 import java.io.InputStream;
007 import java.net.HttpURLConnection;
008 import java.net.URL;
009 import java.net.URLConnection;
010 import java.util.Map;
011 import java.util.Map.Entry;
012 import java.util.HashMap;
013
014 import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
015 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
016 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
017 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
018
019 /**
020 * A {@link TileLoader} implementation that loads tiles from OSM.
021 *
022 * @author Jan Peter Stotz
023 */
024 public class OsmTileLoader implements TileLoader {
025
026 /**
027 * Holds the HTTP headers. Insert e.g. User-Agent here when default should not be used.
028 */
029 public Map<String, String> headers = new HashMap<String, String>();
030
031 public int timeoutConnect = 0;
032 public int timeoutRead = 0;
033
034 protected TileLoaderListener listener;
035
036 public OsmTileLoader(TileLoaderListener listener) {
037 headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*");
038 this.listener = listener;
039 }
040
041 public TileJob createTileLoaderJob(final Tile tile) {
042 return new TileJob() {
043
044 InputStream input = null;
045
046 public void run() {
047 synchronized (tile) {
048 if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
049 return;
050 tile.loaded = false;
051 tile.error = false;
052 tile.loading = true;
053 }
054 try {
055 URLConnection conn = loadTileFromOsm(tile);
056 loadTileMetadata(tile, conn);
057 if ("no-tile".equals(tile.getValue("tile-info"))) {
058 tile.setError("No tile at this zoom level");
059 } else {
060 input = conn.getInputStream();
061 tile.loadImage(input);
062 input.close();
063 input = null;
064 }
065 tile.setLoaded(true);
066 listener.tileLoadingFinished(tile, true);
067 } catch (Exception e) {
068 tile.setError(e.getMessage());
069 listener.tileLoadingFinished(tile, false);
070 if (input == null) {
071 try {
072 System.err.println("Failed loading " + tile.getUrl() +": " + e.getMessage());
073 } catch(IOException i) {
074 }
075 }
076 } finally {
077 tile.loading = false;
078 tile.setLoaded(true);
079 }
080 }
081
082 public Tile getTile() {
083 return tile;
084 }
085 };
086 }
087
088 protected URLConnection loadTileFromOsm(Tile tile) throws IOException {
089 URL url;
090 url = new URL(tile.getUrl());
091 URLConnection urlConn = url.openConnection();
092 if (urlConn instanceof HttpURLConnection) {
093 prepareHttpUrlConnection((HttpURLConnection)urlConn);
094 }
095 urlConn.setReadTimeout(30000); // 30 seconds read timeout
096 return urlConn;
097 }
098
099 protected void loadTileMetadata(Tile tile, URLConnection urlConn) {
100 String str = urlConn.getHeaderField("X-VE-TILEMETA-CaptureDatesRange");
101 if (str != null) {
102 tile.putValue("capture-date", str);
103 }
104 str = urlConn.getHeaderField("X-VE-Tile-Info");
105 if (str != null) {
106 tile.putValue("tile-info", str);
107 }
108 }
109
110 protected void prepareHttpUrlConnection(HttpURLConnection urlConn) {
111 for(Entry<String, String> e : headers.entrySet()) {
112 urlConn.setRequestProperty(e.getKey(), e.getValue());
113 }
114 if(timeoutConnect != 0)
115 urlConn.setConnectTimeout(timeoutConnect);
116 if(timeoutRead != 0)
117 urlConn.setReadTimeout(timeoutRead);
118 }
119
120 @Override
121 public String toString() {
122 return getClass().getSimpleName();
123 }
124
125 }