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

Last change on this file since 7518 was 7434, checked in by Don-vip, 10 years ago

fix #8885 (see #4614) - add offline mode with new command line argument --offline which can take one of several of these values (comma separated):

  • josm_website: to disable all accesses to JOSM website (when not cached, disables Getting Started page, help, plugin list, styles, imagery, presets, rules)
  • osm_api: to disable all accesses to OSM API (disables download, upload, changeset queries, history, user message notification)
  • all: alias to disable all values. Currently equivalent to "josm_website,osm_api"

Plus improved javadoc, fixed EDT violations, and fixed a bug with HTTP redirection sent without "Location" header

  • Property svn:eol-style set to native
File size: 14.5 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.osm.DataSet;
23import org.openstreetmap.josm.gui.progress.ProgressMonitor;
24import org.openstreetmap.josm.tools.Utils;
25
26/**
27 * This DataReader reads directly from the REST API of the osm server.
28 *
29 * It supports plain text transfer as well as gzip or deflate encoded transfers;
30 * if compressed transfers are unwanted, set property osm-server.use-compression
31 * to false.
32 *
33 * @author imi
34 */
35public abstract class OsmServerReader extends OsmConnection {
36 private OsmApi api = OsmApi.getOsmApi();
37 private boolean doAuthenticate = false;
38 protected boolean gpxParsedProperly;
39
40 /**
41 * Open a connection to the given url and return a reader on the input stream
42 * from that connection. In case of user cancel, return <code>null</code>.
43 * Relative URL's are directed to API base URL.
44 * @param urlStr The url to connect to.
45 * @param progressMonitor progress monitoring and abort handler
46 * @return A reader reading the input stream (servers answer) or <code>null</code>.
47 * @throws OsmTransferException thrown if data transfer errors occur
48 */
49 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
50 return getInputStream(urlStr, progressMonitor, null);
51 }
52
53 /**
54 * Open a connection to the given url and return a reader on the input stream
55 * from that connection. In case of user cancel, return <code>null</code>.
56 * Relative URL's are directed to API base URL.
57 * @param urlStr The url to connect to.
58 * @param progressMonitor progress monitoring and abort handler
59 * @param reason The reason to show on console. Can be {@code null} if no reason is given
60 * @return A reader reading the input stream (servers answer) or <code>null</code>.
61 * @throws OsmTransferException thrown if data transfer errors occur
62 */
63 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
64 try {
65 api.initialize(progressMonitor);
66 String url = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr);
67 return getInputStreamRaw(url, progressMonitor, reason);
68 } finally {
69 progressMonitor.invalidate();
70 }
71 }
72
73 /**
74 * Return the base URL for relative URL requests
75 * @return base url of API
76 */
77 protected String getBaseUrl() {
78 return api.getBaseUrl();
79 }
80
81 /**
82 * Open a connection to the given url and return a reader on the input stream
83 * from that connection. In case of user cancel, return <code>null</code>.
84 * @param urlStr The exact url to connect to.
85 * @param progressMonitor progress monitoring and abort handler
86 * @return An reader reading the input stream (servers answer) or <code>null</code>.
87 * @throws OsmTransferException thrown if data transfer errors occur
88 */
89 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
90 return getInputStreamRaw(urlStr, progressMonitor, null);
91 }
92
93 /**
94 * Open a connection to the given url and return a reader on the input stream
95 * from that connection. In case of user cancel, return <code>null</code>.
96 * @param urlStr The exact url to connect to.
97 * @param progressMonitor progress monitoring and abort handler
98 * @param reason The reason to show on console. Can be {@code null} if no reason is given
99 * @return An reader reading the input stream (servers answer) or <code>null</code>.
100 * @throws OsmTransferException thrown if data transfer errors occur
101 */
102 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
103 return getInputStreamRaw(urlStr, progressMonitor, reason, false);
104 }
105
106 /**
107 * Open a connection to the given url and return a reader on the input stream
108 * from that connection. In case of user cancel, return <code>null</code>.
109 * @param urlStr The exact url to connect to.
110 * @param progressMonitor progress monitoring and abort handler
111 * @param reason The reason to show on console. Can be {@code null} if no reason is given
112 * @param uncompressAccordingToContentDisposition Whether to inspect the HTTP header {@code Content-Disposition}
113 * for {@code filename} and uncompress a gzip/bzip2 stream.
114 * @return An reader reading the input stream (servers answer) or <code>null</code>.
115 * @throws OsmTransferException thrown if data transfer errors occur
116 */
117 @SuppressWarnings("resource")
118 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, boolean uncompressAccordingToContentDisposition) throws OsmTransferException {
119 try {
120 OnlineResource.JOSM_WEBSITE.checkOfflineAccess(urlStr, Main.getJOSMWebsite());
121 OnlineResource.OSM_API.checkOfflineAccess(urlStr, Main.pref.get("osm-server.url", OsmApi.DEFAULT_API_URL));
122
123 URL url = null;
124 try {
125 url = new URL(urlStr.replace(" ", "%20"));
126 } catch(MalformedURLException e) {
127 throw new OsmTransferException(e);
128 }
129 try {
130 // fix #7640, see http://www.tikalk.com/java/forums/httpurlconnection-disable-keep-alive
131 activeConnection = Utils.openHttpConnection(url, false);
132 } catch(Exception e) {
133 throw new OsmTransferException(tr("Failed to open connection to API {0}.", url.toExternalForm()), e);
134 }
135 if (cancel) {
136 activeConnection.disconnect();
137 return null;
138 }
139
140 if (doAuthenticate) {
141 addAuth(activeConnection);
142 }
143 if (cancel)
144 throw new OsmTransferCanceledException();
145 if (Main.pref.getBoolean("osm-server.use-compression", true)) {
146 activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
147 }
148
149 activeConnection.setConnectTimeout(Main.pref.getInteger("socket.timeout.connect",15)*1000);
150
151 try {
152 if (reason != null && !reason.isEmpty()) {
153 Main.info("GET " + url + " (" + reason + ")");
154 } else {
155 Main.info("GET " + url);
156 }
157 activeConnection.connect();
158 } catch (Exception e) {
159 Main.error(e);
160 OsmTransferException ote = new OsmTransferException(tr("Could not connect to the OSM server. Please check your internet connection."), e);
161 ote.setUrl(url.toString());
162 throw ote;
163 }
164 try {
165 if (Main.isDebugEnabled()) {
166 Main.debug("RESPONSE: "+activeConnection.getHeaderFields());
167 }
168 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED)
169 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED,null,null);
170
171 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH)
172 throw new OsmTransferCanceledException();
173
174 String encoding = activeConnection.getContentEncoding();
175 if (activeConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
176 String errorHeader = activeConnection.getHeaderField("Error");
177 StringBuilder errorBody = new StringBuilder();
178 try {
179 InputStream i = fixEncoding(activeConnection.getErrorStream(), encoding);
180 if (i != null) {
181 BufferedReader in = new BufferedReader(new InputStreamReader(i, StandardCharsets.UTF_8));
182 String s;
183 while((s = in.readLine()) != null) {
184 errorBody.append(s);
185 errorBody.append("\n");
186 }
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}
Note: See TracBrowser for help on using the repository browser.