001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.io; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.io.BufferedReader; 007 import java.io.IOException; 008 import java.io.InputStream; 009 import java.io.InputStreamReader; 010 import java.net.HttpURLConnection; 011 import java.net.MalformedURLException; 012 import java.net.URL; 013 import java.util.zip.GZIPInputStream; 014 import java.util.zip.Inflater; 015 import java.util.zip.InflaterInputStream; 016 017 import org.openstreetmap.josm.Main; 018 import org.openstreetmap.josm.data.gpx.GpxData; 019 import org.openstreetmap.josm.data.osm.DataSet; 020 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 021 022 /** 023 * This DataReader reads directly from the REST API of the osm server. 024 * 025 * It supports plain text transfer as well as gzip or deflate encoded transfers; 026 * if compressed transfers are unwanted, set property osm-server.use-compression 027 * to false. 028 * 029 * @author imi 030 */ 031 public abstract class OsmServerReader extends OsmConnection { 032 private OsmApi api = OsmApi.getOsmApi(); 033 private boolean doAuthenticate = false; 034 protected boolean gpxParsedProperly; 035 036 /** 037 * Open a connection to the given url and return a reader on the input stream 038 * from that connection. In case of user cancel, return <code>null</code>. 039 * @param urlStr The exact url to connect to. 040 * @param pleaseWaitDlg 041 * @return An reader reading the input stream (servers answer) or <code>null</code>. 042 */ 043 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException { 044 try { 045 api.initialize(progressMonitor); 046 urlStr = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr); 047 return getInputStreamRaw(urlStr, progressMonitor); 048 } finally { 049 progressMonitor.invalidate(); 050 } 051 } 052 053 protected String getBaseUrl() { 054 return api.getBaseUrl(); 055 } 056 057 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException { 058 try { 059 URL url = null; 060 try { 061 url = new URL(urlStr.replace(" ", "%20")); 062 } catch(MalformedURLException e) { 063 throw new OsmTransferException(e); 064 } 065 try { 066 activeConnection = (HttpURLConnection)url.openConnection(); 067 // fix #7640, see http://www.tikalk.com/java/forums/httpurlconnection-disable-keep-alive 068 activeConnection.setRequestProperty("Connection", "close"); 069 } catch(Exception e) { 070 throw new OsmTransferException(tr("Failed to open connection to API {0}.", url.toExternalForm()), e); 071 } 072 if (cancel) { 073 activeConnection.disconnect(); 074 return null; 075 } 076 077 if (doAuthenticate) { 078 addAuth(activeConnection); 079 } 080 if (cancel) 081 throw new OsmTransferCanceledException(); 082 if (Main.pref.getBoolean("osm-server.use-compression", true)) { 083 activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate"); 084 } 085 086 activeConnection.setConnectTimeout(Main.pref.getInteger("socket.timeout.connect",15)*1000); 087 088 try { 089 System.out.println("GET " + url); 090 activeConnection.connect(); 091 } catch (Exception e) { 092 e.printStackTrace(); 093 OsmTransferException ote = new OsmTransferException(tr("Could not connect to the OSM server. Please check your internet connection."), e); 094 ote.setUrl(url.toString()); 095 throw ote; 096 } 097 try { 098 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) 099 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED,null,null); 100 101 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH) 102 throw new OsmTransferCanceledException(); 103 104 String encoding = activeConnection.getContentEncoding(); 105 if (activeConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { 106 String errorHeader = activeConnection.getHeaderField("Error"); 107 StringBuilder errorBody = new StringBuilder(); 108 try 109 { 110 InputStream i = FixEncoding(activeConnection.getErrorStream(), encoding); 111 if (i != null) { 112 BufferedReader in = new BufferedReader(new InputStreamReader(i)); 113 String s; 114 while((s = in.readLine()) != null) { 115 errorBody.append(s); 116 errorBody.append("\n"); 117 } 118 } 119 } 120 catch(Exception e) { 121 errorBody.append(tr("Reading error text failed.")); 122 } 123 124 throw new OsmApiException(activeConnection.getResponseCode(), errorHeader, errorBody.toString()); 125 } 126 127 return FixEncoding(new ProgressInputStream(activeConnection, progressMonitor), encoding); 128 } catch(Exception e) { 129 if (e instanceof OsmTransferException) 130 throw (OsmTransferException)e; 131 else 132 throw new OsmTransferException(e); 133 134 } 135 } finally { 136 progressMonitor.invalidate(); 137 } 138 } 139 140 private InputStream FixEncoding(InputStream stream, String encoding) throws IOException 141 { 142 if (encoding != null && encoding.equalsIgnoreCase("gzip")) { 143 stream = new GZIPInputStream(stream); 144 } 145 else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { 146 stream = new InflaterInputStream(stream, new Inflater(true)); 147 } 148 return stream; 149 } 150 151 public abstract DataSet parseOsm(final ProgressMonitor progressMonitor) throws OsmTransferException; 152 153 public DataSet parseOsmChange(final ProgressMonitor progressMonitor) throws OsmTransferException { 154 return null; 155 } 156 157 public DataSet parseOsmChangeBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 158 return null; 159 } 160 161 public DataSet parseOsmChangeGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 162 return null; 163 } 164 165 public GpxData parseRawGps(final ProgressMonitor progressMonitor) throws OsmTransferException { 166 return null; 167 } 168 169 public DataSet parseOsmBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 170 return null; 171 } 172 173 public DataSet parseOsmGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 174 return null; 175 } 176 177 /** 178 * Returns true if this reader is adding authentication credentials to the read 179 * request sent to the server. 180 * 181 * @return true if this reader is adding authentication credentials to the read 182 * request sent to the server 183 */ 184 public boolean isDoAuthenticate() { 185 return doAuthenticate; 186 } 187 188 /** 189 * Sets whether this reader adds authentication credentials to the read 190 * request sent to the server. 191 * 192 * @param doAuthenticate true if this reader adds authentication credentials to the read 193 * request sent to the server 194 */ 195 public void setDoAuthenticate(boolean doAuthenticate) { 196 this.doAuthenticate = doAuthenticate; 197 } 198 199 /** 200 * Determines if the GPX data has been parsed properly. 201 * @return true if the GPX data has been parsed properly, false otherwise 202 * @see GpxReader#parse 203 */ 204 public final boolean isGpxParsedProperly() { 205 return gpxParsedProperly; 206 } 207 }