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

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

Sonar - various performance improvements

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