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 throw new OsmTransferException(tr("Could not connect to the OSM server. Please check your internet connection."), e); 094 } 095 try { 096 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) 097 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED,null,null); 098 099 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH) 100 throw new OsmTransferCanceledException(); 101 102 String encoding = activeConnection.getContentEncoding(); 103 if (activeConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { 104 String errorHeader = activeConnection.getHeaderField("Error"); 105 StringBuilder errorBody = new StringBuilder(); 106 try 107 { 108 InputStream i = FixEncoding(activeConnection.getErrorStream(), encoding); 109 if (i != null) { 110 BufferedReader in = new BufferedReader(new InputStreamReader(i)); 111 String s; 112 while((s = in.readLine()) != null) { 113 errorBody.append(s); 114 errorBody.append("\n"); 115 } 116 } 117 } 118 catch(Exception e) { 119 errorBody.append(tr("Reading error text failed.")); 120 } 121 122 throw new OsmApiException(activeConnection.getResponseCode(), errorHeader, errorBody.toString()); 123 } 124 125 return FixEncoding(new ProgressInputStream(activeConnection, progressMonitor), encoding); 126 } catch(Exception e) { 127 if (e instanceof OsmTransferException) 128 throw (OsmTransferException)e; 129 else 130 throw new OsmTransferException(e); 131 132 } 133 } finally { 134 progressMonitor.invalidate(); 135 } 136 } 137 138 private InputStream FixEncoding(InputStream stream, String encoding) throws IOException 139 { 140 if (encoding != null && encoding.equalsIgnoreCase("gzip")) { 141 stream = new GZIPInputStream(stream); 142 } 143 else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { 144 stream = new InflaterInputStream(stream, new Inflater(true)); 145 } 146 return stream; 147 } 148 149 public abstract DataSet parseOsm(final ProgressMonitor progressMonitor) throws OsmTransferException; 150 151 public DataSet parseOsmChange(final ProgressMonitor progressMonitor) throws OsmTransferException { 152 return null; 153 } 154 155 public DataSet parseOsmChangeBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 156 return null; 157 } 158 159 public DataSet parseOsmChangeGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 160 return null; 161 } 162 163 public GpxData parseRawGps(final ProgressMonitor progressMonitor) throws OsmTransferException { 164 return null; 165 } 166 167 public DataSet parseOsmBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 168 return null; 169 } 170 171 public DataSet parseOsmGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 172 return null; 173 } 174 175 /** 176 * Returns true if this reader is adding authentication credentials to the read 177 * request sent to the server. 178 * 179 * @return true if this reader is adding authentication credentials to the read 180 * request sent to the server 181 */ 182 public boolean isDoAuthenticate() { 183 return doAuthenticate; 184 } 185 186 /** 187 * Sets whether this reader adds authentication credentials to the read 188 * request sent to the server. 189 * 190 * @param doAuthenticate true if this reader adds authentication credentials to the read 191 * request sent to the server 192 */ 193 public void setDoAuthenticate(boolean doAuthenticate) { 194 this.doAuthenticate = doAuthenticate; 195 } 196 197 /** 198 * Determines if the GPX data has been parsed properly. 199 * @return true if the GPX data has been parsed properly, false otherwise 200 * @see GpxReader#parse 201 */ 202 public final boolean isGpxParsedProperly() { 203 return gpxParsedProperly; 204 } 205 }