source: josm/trunk/src/org/openstreetmap/josm/io/OsmServerReader.java@ 8620

Last change on this file since 8620 was 8563, checked in by Don-vip, 9 years ago

fix #7813 - proper timeouts when connecting to OSM server (patch by anirud)

  • Property svn:eol-style set to native
File size: 16.0 KB
RevLine 
[6380]1// License: GPL. For details, see LICENSE file.
[18]2package org.openstreetmap.josm.io;
3
[916]4import static org.openstreetmap.josm.tools.I18n.tr;
5
[1670]6import java.io.BufferedReader;
[3511]7import java.io.IOException;
[103]8import java.io.InputStream;
[1670]9import java.io.InputStreamReader;
[18]10import java.net.HttpURLConnection;
[1670]11import java.net.MalformedURLException;
[18]12import java.net.URL;
[7082]13import java.nio.charset.StandardCharsets;
[6803]14import java.util.List;
15import java.util.Map;
[1670]16import java.util.zip.GZIPInputStream;
[228]17import java.util.zip.Inflater;
18import java.util.zip.InflaterInputStream;
[18]19
[34]20import org.openstreetmap.josm.Main;
[4521]21import org.openstreetmap.josm.data.gpx.GpxData;
[7531]22import org.openstreetmap.josm.data.notes.Note;
[1146]23import org.openstreetmap.josm.data.osm.DataSet;
[1811]24import org.openstreetmap.josm.gui.progress.ProgressMonitor;
[5587]25import org.openstreetmap.josm.tools.Utils;
[18]26
27/**
[228]28 * This DataReader reads directly from the REST API of the osm server.
[1169]29 *
[228]30 * It supports plain text transfer as well as gzip or deflate encoded transfers;
31 * if compressed transfers are unwanted, set property osm-server.use-compression
32 * to false.
[153]33 *
[18]34 * @author imi
35 */
[1146]36public abstract class OsmServerReader extends OsmConnection {
[1664]37 private OsmApi api = OsmApi.getOsmApi();
[2124]38 private boolean doAuthenticate = false;
[5494]39 protected boolean gpxParsedProperly;
[1664]40
[1169]41 /**
42 * Open a connection to the given url and return a reader on the input stream
43 * from that connection. In case of user cancel, return <code>null</code>.
[5863]44 * Relative URL's are directed to API base URL.
45 * @param urlStr The url to connect to.
46 * @param progressMonitor progress monitoring and abort handler
[6695]47 * @return A reader reading the input stream (servers answer) or <code>null</code>.
[8291]48 * @throws OsmTransferException if data transfer errors occur
[1169]49 */
[1811]50 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
[6695]51 return getInputStream(urlStr, progressMonitor, null);
52 }
53
54 /**
55 * Open a connection to the given url and return a reader on the input stream
56 * from that connection. In case of user cancel, return <code>null</code>.
57 * Relative URL's are directed to API base URL.
58 * @param urlStr The url to connect to.
59 * @param progressMonitor progress monitoring and abort handler
60 * @param reason The reason to show on console. Can be {@code null} if no reason is given
61 * @return A reader reading the input stream (servers answer) or <code>null</code>.
[8291]62 * @throws OsmTransferException if data transfer errors occur
[6695]63 */
64 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
[1875]65 try {
[2035]66 api.initialize(progressMonitor);
[6695]67 String url = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr);
68 return getInputStreamRaw(url, progressMonitor, reason);
[1875]69 } finally {
70 progressMonitor.invalidate();
71 }
[1670]72 }
[1664]73
[5863]74 /**
[6695]75 * Return the base URL for relative URL requests
[5863]76 * @return base url of API
77 */
[5097]78 protected String getBaseUrl() {
79 return api.getBaseUrl();
80 }
81
[5863]82 /**
83 * Open a connection to the given url and return a reader on the input stream
84 * from that connection. In case of user cancel, return <code>null</code>.
85 * @param urlStr The exact url to connect to.
86 * @param progressMonitor progress monitoring and abort handler
87 * @return An reader reading the input stream (servers answer) or <code>null</code>.
[8291]88 * @throws OsmTransferException if data transfer errors occur
[5863]89 */
[1811]90 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
[6695]91 return getInputStreamRaw(urlStr, progressMonitor, null);
92 }
[6787]93
[6695]94 /**
95 * Open a connection to the given url and return a reader on the input stream
96 * from that connection. In case of user cancel, return <code>null</code>.
97 * @param urlStr The exact url to connect to.
98 * @param progressMonitor progress monitoring and abort handler
99 * @param reason The reason to show on console. Can be {@code null} if no reason is given
100 * @return An reader reading the input stream (servers answer) or <code>null</code>.
[8291]101 * @throws OsmTransferException if data transfer errors occur
[6695]102 */
103 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
[6803]104 return getInputStreamRaw(urlStr, progressMonitor, reason, false);
105 }
106
107 /**
108 * Open a connection to the given url and return a reader on the input stream
109 * from that connection. In case of user cancel, return <code>null</code>.
110 * @param urlStr The exact url to connect to.
111 * @param progressMonitor progress monitoring and abort handler
112 * @param reason The reason to show on console. Can be {@code null} if no reason is given
113 * @param uncompressAccordingToContentDisposition Whether to inspect the HTTP header {@code Content-Disposition}
114 * for {@code filename} and uncompress a gzip/bzip2 stream.
115 * @return An reader reading the input stream (servers answer) or <code>null</code>.
[8291]116 * @throws OsmTransferException if data transfer errors occur
[6803]117 */
[7033]118 @SuppressWarnings("resource")
[8509]119 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason,
120 boolean uncompressAccordingToContentDisposition) throws OsmTransferException {
[1608]121 try {
[7434]122 OnlineResource.JOSM_WEBSITE.checkOfflineAccess(urlStr, Main.getJOSMWebsite());
123 OnlineResource.OSM_API.checkOfflineAccess(urlStr, Main.pref.get("osm-server.url", OsmApi.DEFAULT_API_URL));
124
[1875]125 URL url = null;
126 try {
[3021]127 url = new URL(urlStr.replace(" ", "%20"));
[8510]128 } catch (MalformedURLException e) {
[1875]129 throw new OsmTransferException(e);
130 }
131 try {
[5324]132 // fix #7640, see http://www.tikalk.com/java/forums/httpurlconnection-disable-keep-alive
[5587]133 activeConnection = Utils.openHttpConnection(url, false);
[8510]134 } catch (Exception e) {
[2181]135 throw new OsmTransferException(tr("Failed to open connection to API {0}.", url.toExternalForm()), e);
[1875]136 }
[8563]137 Utils.setupURLConnection(activeConnection);
[1875]138 if (cancel) {
139 activeConnection.disconnect();
140 return null;
141 }
[228]142
[2641]143 if (doAuthenticate) {
144 addAuth(activeConnection);
[2124]145 }
[2641]146 if (cancel)
[8415]147 throw new OsmTransferCanceledException("Operation canceled");
[1875]148 if (Main.pref.getBoolean("osm-server.use-compression", true)) {
149 activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
150 }
[1169]151
[1875]152 try {
[6695]153 if (reason != null && !reason.isEmpty()) {
154 Main.info("GET " + url + " (" + reason + ")");
155 } else {
156 Main.info("GET " + url);
157 }
[1875]158 activeConnection.connect();
159 } catch (Exception e) {
[6643]160 Main.error(e);
[8509]161 OsmTransferException ote = new OsmTransferException(
162 tr("Could not connect to the OSM server. Please check your internet connection."), e);
[5575]163 ote.setUrl(url.toString());
164 throw ote;
[1875]165 }
166 try {
[6852]167 if (Main.isDebugEnabled()) {
168 Main.debug("RESPONSE: "+activeConnection.getHeaderFields());
169 }
[2641]170 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED)
[8510]171 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED, null, null);
[1353]172
[2641]173 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH)
[8415]174 throw new OsmTransferCanceledException("Proxy Authentication Required");
[2641]175
[3511]176 String encoding = activeConnection.getContentEncoding();
[1875]177 if (activeConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
178 String errorHeader = activeConnection.getHeaderField("Error");
179 StringBuilder errorBody = new StringBuilder();
[6787]180 try {
181 InputStream i = fixEncoding(activeConnection.getErrorStream(), encoding);
[3511]182 if (i != null) {
[7082]183 BufferedReader in = new BufferedReader(new InputStreamReader(i, StandardCharsets.UTF_8));
[3511]184 String s;
[8510]185 while ((s = in.readLine()) != null) {
[3511]186 errorBody.append(s);
[8390]187 errorBody.append('\n');
[3511]188 }
[1875]189 }
[8510]190 } catch (Exception e) {
[3511]191 errorBody.append(tr("Reading error text failed."));
192 }
[1875]193
[5584]194 throw new OsmApiException(activeConnection.getResponseCode(), errorHeader, errorBody.toString(), url.toString());
[1670]195 }
[1169]196
[6803]197 InputStream in = new ProgressInputStream(activeConnection, progressMonitor);
198 if (uncompressAccordingToContentDisposition) {
199 in = uncompressAccordingToContentDisposition(in, activeConnection.getHeaderFields());
200 }
201 return fixEncoding(in, encoding);
[6246]202 } catch (OsmTransferException e) {
203 throw e;
204 } catch (Exception e) {
205 throw new OsmTransferException(e);
[1670]206 }
[1875]207 } finally {
208 progressMonitor.invalidate();
[1169]209 }
210 }
211
[6787]212 private InputStream fixEncoding(InputStream stream, String encoding) throws IOException {
[6089]213 if ("gzip".equalsIgnoreCase(encoding)) {
[3511]214 stream = new GZIPInputStream(stream);
[6787]215 } else if ("deflate".equalsIgnoreCase(encoding)) {
[3511]216 stream = new InflaterInputStream(stream, new Inflater(true));
217 }
218 return stream;
219 }
220
[6803]221 private InputStream uncompressAccordingToContentDisposition(InputStream stream, Map<String, List<String>> headerFields) throws IOException {
[7267]222 List<String> field = headerFields.get("Content-Disposition");
223 if (field != null && field.toString().contains(".gz\"")) {
[6803]224 return Compression.GZIP.getUncompressedInputStream(stream);
[7267]225 } else if (field != null && field.toString().contains(".bz2\"")) {
[6803]226 return Compression.BZIP2.getUncompressedInputStream(stream);
227 } else {
228 return stream;
229 }
230 }
231
[6244]232 /**
233 * Download OSM files from somewhere
234 * @param progressMonitor The progress monitor
235 * @return The corresponding dataset
[6643]236 * @throws OsmTransferException if any error occurs
[6244]237 */
[5317]238 public abstract DataSet parseOsm(final ProgressMonitor progressMonitor) throws OsmTransferException;
[1169]239
[6244]240 /**
241 * Download OSM Change files from somewhere
242 * @param progressMonitor The progress monitor
243 * @return The corresponding dataset
[6643]244 * @throws OsmTransferException if any error occurs
[6244]245 */
[5317]246 public DataSet parseOsmChange(final ProgressMonitor progressMonitor) throws OsmTransferException {
[4530]247 return null;
248 }
[5361]249
[6244]250 /**
251 * Download BZip2-compressed OSM Change files from somewhere
252 * @param progressMonitor The progress monitor
253 * @return The corresponding dataset
[6643]254 * @throws OsmTransferException if any error occurs
[6244]255 */
[5361]256 public DataSet parseOsmChangeBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
257 return null;
258 }
259
[6244]260 /**
261 * Download GZip-compressed OSM Change files from somewhere
262 * @param progressMonitor The progress monitor
263 * @return The corresponding dataset
[6643]264 * @throws OsmTransferException if any error occurs
[6244]265 */
[5361]266 public DataSet parseOsmChangeGzip(final ProgressMonitor progressMonitor) throws OsmTransferException {
267 return null;
268 }
269
[6244]270 /**
271 * Retrieve raw gps waypoints from the server API.
272 * @param progressMonitor The progress monitor
273 * @return The corresponding GPX tracks
274 * @throws OsmTransferException if any error occurs
275 */
[5317]276 public GpxData parseRawGps(final ProgressMonitor progressMonitor) throws OsmTransferException {
[4521]277 return null;
278 }
[5317]279
[6244]280 /**
281 * Retrieve BZip2-compressed GPX files from somewhere.
282 * @param progressMonitor The progress monitor
283 * @return The corresponding GPX tracks
284 * @throws OsmTransferException if any error occurs
285 * @since 6244
286 */
287 public GpxData parseRawGpsBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
288 return null;
289 }
290
291 /**
292 * Download BZip2-compressed OSM files from somewhere
293 * @param progressMonitor The progress monitor
294 * @return The corresponding dataset
[6643]295 * @throws OsmTransferException if any error occurs
[6244]296 */
[5317]297 public DataSet parseOsmBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
298 return null;
299 }
[5361]300
[6244]301 /**
302 * Download GZip-compressed OSM files from somewhere
303 * @param progressMonitor The progress monitor
304 * @return The corresponding dataset
[6643]305 * @throws OsmTransferException if any error occurs
[6244]306 */
[5361]307 public DataSet parseOsmGzip(final ProgressMonitor progressMonitor) throws OsmTransferException {
308 return null;
309 }
310
[2124]311 /**
[6882]312 * Download Zip-compressed OSM files from somewhere
313 * @param progressMonitor The progress monitor
314 * @return The corresponding dataset
315 * @throws OsmTransferException if any error occurs
316 * @since 6882
317 */
318 public DataSet parseOsmZip(final ProgressMonitor progressMonitor) throws OsmTransferException {
319 return null;
320 }
321
322 /**
[2124]323 * Returns true if this reader is adding authentication credentials to the read
324 * request sent to the server.
[2512]325 *
[2124]326 * @return true if this reader is adding authentication credentials to the read
327 * request sent to the server
328 */
329 public boolean isDoAuthenticate() {
330 return doAuthenticate;
331 }
332
333 /**
334 * Sets whether this reader adds authentication credentials to the read
335 * request sent to the server.
[2512]336 *
[2124]337 * @param doAuthenticate true if this reader adds authentication credentials to the read
338 * request sent to the server
339 */
340 public void setDoAuthenticate(boolean doAuthenticate) {
341 this.doAuthenticate = doAuthenticate;
342 }
[6070]343
[5494]344 /**
345 * Determines if the GPX data has been parsed properly.
346 * @return true if the GPX data has been parsed properly, false otherwise
347 * @see GpxReader#parse
348 */
349 public final boolean isGpxParsedProperly() {
350 return gpxParsedProperly;
351 }
[7531]352
353 /**
354 * Downloads notes from the API, given API limit parameters
355 *
[8218]356 * @param noteLimit How many notes to download.
[7531]357 * @param daysClosed Return notes closed this many days in the past. -1 means all notes, ever. 0 means only unresolved notes.
358 * @param progressMonitor Progress monitor for user feedback
359 * @return List of notes returned by the API
360 * @throws OsmTransferException if any errors happen
361 */
[8218]362 public List<Note> parseNotes(int noteLimit, int daysClosed, ProgressMonitor progressMonitor) throws OsmTransferException {
[7531]363 return null;
364 }
365
366 /**
367 * Downloads notes from a given raw URL. The URL is assumed to be complete and no API limits are added
368 *
[8470]369 * @param progressMonitor progress monitor
[7531]370 * @return A list of notes parsed from the URL
[8470]371 * @throws OsmTransferException if any error occurs during dialog with OSM API
[7531]372 */
373 public List<Note> parseRawNotes(final ProgressMonitor progressMonitor) throws OsmTransferException {
374 return null;
375 }
376
377 /**
378 * Download notes from a URL that contains a bzip2 compressed notes dump file
[8470]379 * @param progressMonitor progress monitor
[7531]380 * @return A list of notes parsed from the URL
[8470]381 * @throws OsmTransferException if any error occurs during dialog with OSM API
[7531]382 */
383 public List<Note> parseRawNotesBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
384 return null;
385 }
[18]386}
Note: See TracBrowser for help on using the repository browser.