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

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

fix #9906 - fix reliance on default encoding

  • Property svn:eol-style set to native
File size: 14.2 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.util.List;
14import java.util.Map;
15import java.util.zip.GZIPInputStream;
16import java.util.zip.Inflater;
17import java.util.zip.InflaterInputStream;
18
19import org.openstreetmap.josm.Main;
20import org.openstreetmap.josm.data.gpx.GpxData;
21import org.openstreetmap.josm.data.osm.DataSet;
22import org.openstreetmap.josm.gui.progress.ProgressMonitor;
23import org.openstreetmap.josm.tools.Utils;
24
25/**
26 * This DataReader reads directly from the REST API of the osm server.
27 *
28 * It supports plain text transfer as well as gzip or deflate encoded transfers;
29 * if compressed transfers are unwanted, set property osm-server.use-compression
30 * to false.
31 *
32 * @author imi
33 */
34public abstract class OsmServerReader extends OsmConnection {
35 private OsmApi api = OsmApi.getOsmApi();
36 private boolean doAuthenticate = false;
37 protected boolean gpxParsedProperly;
38
39 /**
40 * Open a connection to the given url and return a reader on the input stream
41 * from that connection. In case of user cancel, return <code>null</code>.
42 * Relative URL's are directed to API base URL.
43 * @param urlStr The url to connect to.
44 * @param progressMonitor progress monitoring and abort handler
45 * @return A reader reading the input stream (servers answer) or <code>null</code>.
46 * @throws OsmTransferException thrown if data transfer errors occur
47 */
48 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
49 return getInputStream(urlStr, progressMonitor, null);
50 }
51
52 /**
53 * Open a connection to the given url and return a reader on the input stream
54 * from that connection. In case of user cancel, return <code>null</code>.
55 * Relative URL's are directed to API base URL.
56 * @param urlStr The url to connect to.
57 * @param progressMonitor progress monitoring and abort handler
58 * @param reason The reason to show on console. Can be {@code null} if no reason is given
59 * @return A reader reading the input stream (servers answer) or <code>null</code>.
60 * @throws OsmTransferException thrown if data transfer errors occur
61 */
62 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
63 try {
64 api.initialize(progressMonitor);
65 String url = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr);
66 return getInputStreamRaw(url, progressMonitor, reason);
67 } finally {
68 progressMonitor.invalidate();
69 }
70 }
71
72 /**
73 * Return the base URL for relative URL requests
74 * @return base url of API
75 */
76 protected String getBaseUrl() {
77 return api.getBaseUrl();
78 }
79
80 /**
81 * Open a connection to the given url and return a reader on the input stream
82 * from that connection. In case of user cancel, return <code>null</code>.
83 * @param urlStr The exact url to connect to.
84 * @param progressMonitor progress monitoring and abort handler
85 * @return An reader reading the input stream (servers answer) or <code>null</code>.
86 * @throws OsmTransferException thrown if data transfer errors occur
87 */
88 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
89 return getInputStreamRaw(urlStr, progressMonitor, null);
90 }
91
92 /**
93 * Open a connection to the given url and return a reader on the input stream
94 * from that connection. In case of user cancel, return <code>null</code>.
95 * @param urlStr The exact url to connect to.
96 * @param progressMonitor progress monitoring and abort handler
97 * @param reason The reason to show on console. Can be {@code null} if no reason is given
98 * @return An reader reading the input stream (servers answer) or <code>null</code>.
99 * @throws OsmTransferException thrown if data transfer errors occur
100 */
101 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException {
102 return getInputStreamRaw(urlStr, progressMonitor, reason, false);
103 }
104
105 /**
106 * Open a connection to the given url and return a reader on the input stream
107 * from that connection. In case of user cancel, return <code>null</code>.
108 * @param urlStr The exact url to connect to.
109 * @param progressMonitor progress monitoring and abort handler
110 * @param reason The reason to show on console. Can be {@code null} if no reason is given
111 * @param uncompressAccordingToContentDisposition Whether to inspect the HTTP header {@code Content-Disposition}
112 * for {@code filename} and uncompress a gzip/bzip2 stream.
113 * @return An reader reading the input stream (servers answer) or <code>null</code>.
114 * @throws OsmTransferException thrown if data transfer errors occur
115 */
116 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, boolean uncompressAccordingToContentDisposition) throws OsmTransferException {
117 try {
118 URL url = null;
119 try {
120 url = new URL(urlStr.replace(" ", "%20"));
121 } catch(MalformedURLException e) {
122 throw new OsmTransferException(e);
123 }
124 try {
125 // fix #7640, see http://www.tikalk.com/java/forums/httpurlconnection-disable-keep-alive
126 activeConnection = Utils.openHttpConnection(url, false);
127 } catch(Exception e) {
128 throw new OsmTransferException(tr("Failed to open connection to API {0}.", url.toExternalForm()), e);
129 }
130 if (cancel) {
131 activeConnection.disconnect();
132 return null;
133 }
134
135 if (doAuthenticate) {
136 addAuth(activeConnection);
137 }
138 if (cancel)
139 throw new OsmTransferCanceledException();
140 if (Main.pref.getBoolean("osm-server.use-compression", true)) {
141 activeConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
142 }
143
144 activeConnection.setConnectTimeout(Main.pref.getInteger("socket.timeout.connect",15)*1000);
145
146 try {
147 if (reason != null && !reason.isEmpty()) {
148 Main.info("GET " + url + " (" + reason + ")");
149 } else {
150 Main.info("GET " + url);
151 }
152 activeConnection.connect();
153 } catch (Exception e) {
154 Main.error(e);
155 OsmTransferException ote = new OsmTransferException(tr("Could not connect to the OSM server. Please check your internet connection."), e);
156 ote.setUrl(url.toString());
157 throw ote;
158 }
159 try {
160 if (Main.isDebugEnabled()) {
161 Main.debug("RESPONSE: "+activeConnection.getHeaderFields());
162 }
163 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED)
164 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED,null,null);
165
166 if (activeConnection.getResponseCode() == HttpURLConnection.HTTP_PROXY_AUTH)
167 throw new OsmTransferCanceledException();
168
169 String encoding = activeConnection.getContentEncoding();
170 if (activeConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
171 String errorHeader = activeConnection.getHeaderField("Error");
172 StringBuilder errorBody = new StringBuilder();
173 try {
174 InputStream i = fixEncoding(activeConnection.getErrorStream(), encoding);
175 if (i != null) {
176 BufferedReader in = new BufferedReader(new InputStreamReader(i, Utils.UTF_8));
177 String s;
178 while((s = in.readLine()) != null) {
179 errorBody.append(s);
180 errorBody.append("\n");
181 }
182 }
183 }
184 catch(Exception e) {
185 errorBody.append(tr("Reading error text failed."));
186 }
187
188 throw new OsmApiException(activeConnection.getResponseCode(), errorHeader, errorBody.toString(), url.toString());
189 }
190
191 InputStream in = new ProgressInputStream(activeConnection, progressMonitor);
192 if (uncompressAccordingToContentDisposition) {
193 in = uncompressAccordingToContentDisposition(in, activeConnection.getHeaderFields());
194 }
195 return fixEncoding(in, encoding);
196 } catch (OsmTransferException e) {
197 throw e;
198 } catch (Exception e) {
199 throw new OsmTransferException(e);
200 }
201 } finally {
202 progressMonitor.invalidate();
203 }
204 }
205
206 private InputStream fixEncoding(InputStream stream, String encoding) throws IOException {
207 if ("gzip".equalsIgnoreCase(encoding)) {
208 stream = new GZIPInputStream(stream);
209 } else if ("deflate".equalsIgnoreCase(encoding)) {
210 stream = new InflaterInputStream(stream, new Inflater(true));
211 }
212 return stream;
213 }
214
215 private InputStream uncompressAccordingToContentDisposition(InputStream stream, Map<String, List<String>> headerFields) throws IOException {
216 if (headerFields.get("Content-Disposition").toString().contains(".gz\"")) {
217 return Compression.GZIP.getUncompressedInputStream(stream);
218 } else if (headerFields.get("Content-Disposition").toString().contains(".bz2\"")) {
219 return Compression.BZIP2.getUncompressedInputStream(stream);
220 } else {
221 return stream;
222 }
223 }
224
225 /**
226 * Download OSM files from somewhere
227 * @param progressMonitor The progress monitor
228 * @return The corresponding dataset
229 * @throws OsmTransferException if any error occurs
230 */
231 public abstract DataSet parseOsm(final ProgressMonitor progressMonitor) throws OsmTransferException;
232
233 /**
234 * Download OSM Change files from somewhere
235 * @param progressMonitor The progress monitor
236 * @return The corresponding dataset
237 * @throws OsmTransferException if any error occurs
238 */
239 public DataSet parseOsmChange(final ProgressMonitor progressMonitor) throws OsmTransferException {
240 return null;
241 }
242
243 /**
244 * Download BZip2-compressed OSM Change files from somewhere
245 * @param progressMonitor The progress monitor
246 * @return The corresponding dataset
247 * @throws OsmTransferException if any error occurs
248 */
249 public DataSet parseOsmChangeBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
250 return null;
251 }
252
253 /**
254 * Download GZip-compressed OSM Change files from somewhere
255 * @param progressMonitor The progress monitor
256 * @return The corresponding dataset
257 * @throws OsmTransferException if any error occurs
258 */
259 public DataSet parseOsmChangeGzip(final ProgressMonitor progressMonitor) throws OsmTransferException {
260 return null;
261 }
262
263 /**
264 * Retrieve raw gps waypoints from the server API.
265 * @param progressMonitor The progress monitor
266 * @return The corresponding GPX tracks
267 * @throws OsmTransferException if any error occurs
268 */
269 public GpxData parseRawGps(final ProgressMonitor progressMonitor) throws OsmTransferException {
270 return null;
271 }
272
273 /**
274 * Retrieve BZip2-compressed GPX files from somewhere.
275 * @param progressMonitor The progress monitor
276 * @return The corresponding GPX tracks
277 * @throws OsmTransferException if any error occurs
278 * @since 6244
279 */
280 public GpxData parseRawGpsBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
281 return null;
282 }
283
284 /**
285 * Download BZip2-compressed OSM files from somewhere
286 * @param progressMonitor The progress monitor
287 * @return The corresponding dataset
288 * @throws OsmTransferException if any error occurs
289 */
290 public DataSet parseOsmBzip2(final ProgressMonitor progressMonitor) throws OsmTransferException {
291 return null;
292 }
293
294 /**
295 * Download GZip-compressed OSM files from somewhere
296 * @param progressMonitor The progress monitor
297 * @return The corresponding dataset
298 * @throws OsmTransferException if any error occurs
299 */
300 public DataSet parseOsmGzip(final ProgressMonitor progressMonitor) throws OsmTransferException {
301 return null;
302 }
303
304 /**
305 * Download Zip-compressed OSM files from somewhere
306 * @param progressMonitor The progress monitor
307 * @return The corresponding dataset
308 * @throws OsmTransferException if any error occurs
309 * @since 6882
310 */
311 public DataSet parseOsmZip(final ProgressMonitor progressMonitor) throws OsmTransferException {
312 return null;
313 }
314
315 /**
316 * Returns true if this reader is adding authentication credentials to the read
317 * request sent to the server.
318 *
319 * @return true if this reader is adding authentication credentials to the read
320 * request sent to the server
321 */
322 public boolean isDoAuthenticate() {
323 return doAuthenticate;
324 }
325
326 /**
327 * Sets whether this reader adds authentication credentials to the read
328 * request sent to the server.
329 *
330 * @param doAuthenticate true if this reader adds authentication credentials to the read
331 * request sent to the server
332 */
333 public void setDoAuthenticate(boolean doAuthenticate) {
334 this.doAuthenticate = doAuthenticate;
335 }
336
337 /**
338 * Determines if the GPX data has been parsed properly.
339 * @return true if the GPX data has been parsed properly, false otherwise
340 * @see GpxReader#parse
341 */
342 public final boolean isGpxParsedProperly() {
343 return gpxParsedProperly;
344 }
345}
Note: See TracBrowser for help on using the repository browser.