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