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    }