001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.IOException; 007import java.io.InputStream; 008import java.net.HttpURLConnection; 009import java.net.MalformedURLException; 010import java.net.URL; 011import java.util.List; 012 013import org.openstreetmap.josm.Main; 014import org.openstreetmap.josm.data.gpx.GpxData; 015import org.openstreetmap.josm.data.notes.Note; 016import org.openstreetmap.josm.data.osm.DataSet; 017import org.openstreetmap.josm.gui.progress.ProgressMonitor; 018import org.openstreetmap.josm.tools.HttpClient; 019 020/** 021 * This DataReader reads directly from the REST API of the osm server. 022 * 023 * It supports plain text transfer as well as gzip or deflate encoded transfers; 024 * if compressed transfers are unwanted, set property osm-server.use-compression 025 * to false. 026 * 027 * @author imi 028 */ 029public abstract class OsmServerReader extends OsmConnection { 030 private final OsmApi api = OsmApi.getOsmApi(); 031 private boolean doAuthenticate; 032 protected boolean gpxParsedProperly; 033 034 /** 035 * Open a connection to the given url and return a reader on the input stream 036 * from that connection. In case of user cancel, return <code>null</code>. 037 * Relative URL's are directed to API base URL. 038 * @param urlStr The url to connect to. 039 * @param progressMonitor progress monitoring and abort handler 040 * @return A reader reading the input stream (servers answer) or <code>null</code>. 041 * @throws OsmTransferException if data transfer errors occur 042 */ 043 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException { 044 return getInputStream(urlStr, progressMonitor, null); 045 } 046 047 /** 048 * Open a connection to the given url and return a reader on the input stream 049 * from that connection. In case of user cancel, return <code>null</code>. 050 * Relative URL's are directed to API base URL. 051 * @param urlStr The url to connect to. 052 * @param progressMonitor progress monitoring and abort handler 053 * @param reason The reason to show on console. Can be {@code null} if no reason is given 054 * @return A reader reading the input stream (servers answer) or <code>null</code>. 055 * @throws OsmTransferException if data transfer errors occur 056 */ 057 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException { 058 try { 059 api.initialize(progressMonitor); 060 String url = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr); 061 return getInputStreamRaw(url, progressMonitor, reason); 062 } finally { 063 progressMonitor.invalidate(); 064 } 065 } 066 067 /** 068 * Return the base URL for relative URL requests 069 * @return base url of API 070 */ 071 protected String getBaseUrl() { 072 return api.getBaseUrl(); 073 } 074 075 /** 076 * Open a connection to the given url and return a reader on the input stream 077 * from that connection. In case of user cancel, return <code>null</code>. 078 * @param urlStr The exact url to connect to. 079 * @param progressMonitor progress monitoring and abort handler 080 * @return An reader reading the input stream (servers answer) or <code>null</code>. 081 * @throws OsmTransferException if data transfer errors occur 082 */ 083 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException { 084 return getInputStreamRaw(urlStr, progressMonitor, null); 085 } 086 087 /** 088 * Open a connection to the given url and return a reader on the input stream 089 * from that connection. In case of user cancel, return <code>null</code>. 090 * @param urlStr The exact url to connect to. 091 * @param progressMonitor progress monitoring and abort handler 092 * @param reason The reason to show on console. Can be {@code null} if no reason is given 093 * @return An reader reading the input stream (servers answer) or <code>null</code>. 094 * @throws OsmTransferException if data transfer errors occur 095 */ 096 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException { 097 return getInputStreamRaw(urlStr, progressMonitor, reason, false); 098 } 099 100 /** 101 * Open a connection to the given url and return a reader on the input stream 102 * from that connection. In case of user cancel, return <code>null</code>. 103 * @param urlStr The exact url to connect to. 104 * @param progressMonitor progress monitoring and abort handler 105 * @param reason The reason to show on console. Can be {@code null} if no reason is given 106 * @param uncompressAccordingToContentDisposition Whether to inspect the HTTP header {@code Content-Disposition} 107 * for {@code filename} and uncompress a gzip/bzip2 stream. 108 * @return An reader reading the input stream (servers answer) or <code>null</code>. 109 * @throws OsmTransferException if data transfer errors occur 110 */ 111 @SuppressWarnings("resource") 112 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, 113 boolean uncompressAccordingToContentDisposition) throws OsmTransferException { 114 try { 115 OnlineResource.JOSM_WEBSITE.checkOfflineAccess(urlStr, Main.getJOSMWebsite()); 116 OnlineResource.OSM_API.checkOfflineAccess(urlStr, OsmApi.getOsmApi().getServerUrl()); 117 118 URL url = null; 119 try { 120 url = new URL(urlStr.replace(" ", "%20")); 121 } catch (MalformedURLException e) { 122 throw new OsmTransferException(e); 123 } 124 125 if ("file".equals(url.getProtocol())) { 126 try { 127 return url.openStream(); 128 } catch (IOException e) { 129 throw new OsmTransferException(e); 130 } 131 } 132 133 final HttpClient client = HttpClient.create(url); 134 activeConnection = client; 135 client.setReasonForRequest(reason); 136 adaptRequest(client); 137 if (doAuthenticate) { 138 addAuth(client); 139 } 140 if (cancel) 141 throw new OsmTransferCanceledException("Operation canceled"); 142 143 final HttpClient.Response response; 144 try { 145 response = client.connect(progressMonitor); 146 } catch (IOException e) { 147 Main.error(e); 148 OsmTransferException ote = new OsmTransferException( 149 tr("Could not connect to the OSM server. Please check your internet connection."), e); 150 ote.setUrl(url.toString()); 151 throw ote; 152 } 153 try { 154 if (response.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) 155 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED, null, null); 156 157 if (response.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH) 158 throw new OsmTransferCanceledException("Proxy Authentication Required"); 159 160 if (response.getResponseCode() != HttpURLConnection.HTTP_OK) { 161 String errorHeader = response.getHeaderField("Error"); 162 String errorBody = fetchResponseText(response); 163 throw new OsmApiException(response.getResponseCode(), errorHeader, errorBody, url.toString()); 164 } 165 166 response.uncompressAccordingToContentDisposition(uncompressAccordingToContentDisposition); 167 return response.getContent(); 168 } catch (OsmTransferException e) { 169 throw e; 170 } catch (IOException e) { 171 throw new OsmTransferException(e); 172 } 173 } finally { 174 progressMonitor.invalidate(); 175 } 176 } 177 178 private static String fetchResponseText(final HttpClient.Response response) { 179 try { 180 return response.fetchContent(); 181 } catch (IOException e) { 182 Main.error(e); 183 return tr("Reading error text failed."); 184 } 185 } 186 187 /** 188 * Allows subclasses to modify the request. 189 * @param request the prepared request 190 * @since 9308 191 */ 192 protected void adaptRequest(HttpClient request) { 193 } 194 195 /** 196 * Download OSM files from somewhere 197 * @param progressMonitor The progress monitor 198 * @return The corresponding dataset 199 * @throws OsmTransferException if any error occurs 200 */ 201 public abstract DataSet parseOsm(final ProgressMonitor progressMonitor) throws OsmTransferException; 202 203 /** 204 * Download OSM Change files from somewhere 205 * @param progressMonitor The progress monitor 206 * @return The corresponding dataset 207 * @throws OsmTransferException if any error occurs 208 */ 209 public DataSet parseOsmChange(final ProgressMonitor progressMonitor) throws OsmTransferException { 210 return null; 211 } 212 213 /** 214 * Download BZip2-compressed OSM Change files from somewhere 215 * @param progressMonitor The progress monitor 216 * @return The corresponding dataset 217 * @throws OsmTransferException if any error occurs 218 */ 219 public DataSet parseOsmChangeBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 220 return null; 221 } 222 223 /** 224 * Download GZip-compressed OSM Change files from somewhere 225 * @param progressMonitor The progress monitor 226 * @return The corresponding dataset 227 * @throws OsmTransferException if any error occurs 228 */ 229 public DataSet parseOsmChangeGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 230 return null; 231 } 232 233 /** 234 * Retrieve raw gps waypoints from the server API. 235 * @param progressMonitor The progress monitor 236 * @return The corresponding GPX tracks 237 * @throws OsmTransferException if any error occurs 238 */ 239 public GpxData parseRawGps(final ProgressMonitor progressMonitor) throws OsmTransferException { 240 return null; 241 } 242 243 /** 244 * Retrieve BZip2-compressed GPX files from somewhere. 245 * @param progressMonitor The progress monitor 246 * @return The corresponding GPX tracks 247 * @throws OsmTransferException if any error occurs 248 * @since 6244 249 */ 250 public GpxData parseRawGpsBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 251 return null; 252 } 253 254 /** 255 * Download BZip2-compressed OSM files from somewhere 256 * @param progressMonitor The progress monitor 257 * @return The corresponding dataset 258 * @throws OsmTransferException if any error occurs 259 */ 260 public DataSet parseOsmBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 261 return null; 262 } 263 264 /** 265 * Download GZip-compressed OSM files from somewhere 266 * @param progressMonitor The progress monitor 267 * @return The corresponding dataset 268 * @throws OsmTransferException if any error occurs 269 */ 270 public DataSet parseOsmGzip(final ProgressMonitor progressMonitor) throws OsmTransferException { 271 return null; 272 } 273 274 /** 275 * Download Zip-compressed OSM files from somewhere 276 * @param progressMonitor The progress monitor 277 * @return The corresponding dataset 278 * @throws OsmTransferException if any error occurs 279 * @since 6882 280 */ 281 public DataSet parseOsmZip(final ProgressMonitor progressMonitor) throws OsmTransferException { 282 return null; 283 } 284 285 /** 286 * Returns true if this reader is adding authentication credentials to the read 287 * request sent to the server. 288 * 289 * @return true if this reader is adding authentication credentials to the read 290 * request sent to the server 291 */ 292 public boolean isDoAuthenticate() { 293 return doAuthenticate; 294 } 295 296 /** 297 * Sets whether this reader adds authentication credentials to the read 298 * request sent to the server. 299 * 300 * @param doAuthenticate true if this reader adds authentication credentials to the read 301 * request sent to the server 302 */ 303 public void setDoAuthenticate(boolean doAuthenticate) { 304 this.doAuthenticate = doAuthenticate; 305 } 306 307 /** 308 * Determines if the GPX data has been parsed properly. 309 * @return true if the GPX data has been parsed properly, false otherwise 310 * @see GpxReader#parse 311 */ 312 public final boolean isGpxParsedProperly() { 313 return gpxParsedProperly; 314 } 315 316 /** 317 * Downloads notes from the API, given API limit parameters 318 * 319 * @param noteLimit How many notes to download. 320 * @param daysClosed Return notes closed this many days in the past. -1 means all notes, ever. 0 means only unresolved notes. 321 * @param progressMonitor Progress monitor for user feedback 322 * @return List of notes returned by the API 323 * @throws OsmTransferException if any errors happen 324 */ 325 public List<Note> parseNotes(int noteLimit, int daysClosed, ProgressMonitor progressMonitor) throws OsmTransferException { 326 return null; 327 } 328 329 /** 330 * Downloads notes from a given raw URL. The URL is assumed to be complete and no API limits are added 331 * 332 * @param progressMonitor progress monitor 333 * @return A list of notes parsed from the URL 334 * @throws OsmTransferException if any error occurs during dialog with OSM API 335 */ 336 public List<Note> parseRawNotes(final ProgressMonitor progressMonitor) throws OsmTransferException { 337 return null; 338 } 339 340 /** 341 * Download notes from a URL that contains a bzip2 compressed notes dump file 342 * @param progressMonitor progress monitor 343 * @return A list of notes parsed from the URL 344 * @throws OsmTransferException if any error occurs during dialog with OSM API 345 */ 346 public List<Note> parseRawNotesBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException { 347 return null; 348 } 349}