source: josm/trunk/src/org/openstreetmap/josm/io/BoundingBoxDownloader.java@ 11457

Last change on this file since 11457 was 11397, checked in by Don-vip, 7 years ago

sonar - squid:S2259 - Null pointers should not be dereferenced

  • Property svn:eol-style set to native
File size: 10.0 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.IOException;
7import java.io.InputStream;
8import java.net.SocketException;
9import java.util.List;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.data.Bounds;
13import org.openstreetmap.josm.data.DataSource;
14import org.openstreetmap.josm.data.gpx.GpxData;
15import org.openstreetmap.josm.data.notes.Note;
16import org.openstreetmap.josm.data.osm.DataSet;
17import org.openstreetmap.josm.gui.progress.ProgressMonitor;
18import org.openstreetmap.josm.tools.CheckParameterUtil;
19import org.xml.sax.SAXException;
20
21/**
22 * Read content from OSM server for a given bounding box
23 * @since 627
24 */
25public class BoundingBoxDownloader extends OsmServerReader {
26
27 /**
28 * The boundings of the desired map data.
29 */
30 protected final double lat1;
31 protected final double lon1;
32 protected final double lat2;
33 protected final double lon2;
34 protected final boolean crosses180th;
35
36 /**
37 * Constructs a new {@code BoundingBoxDownloader}.
38 * @param downloadArea The area to download
39 */
40 public BoundingBoxDownloader(Bounds downloadArea) {
41 CheckParameterUtil.ensureParameterNotNull(downloadArea, "downloadArea");
42 this.lat1 = downloadArea.getMinLat();
43 this.lon1 = downloadArea.getMinLon();
44 this.lat2 = downloadArea.getMaxLat();
45 this.lon2 = downloadArea.getMaxLon();
46 this.crosses180th = downloadArea.crosses180thMeridian();
47 }
48
49 private GpxData downloadRawGps(Bounds b, ProgressMonitor progressMonitor) throws IOException, OsmTransferException, SAXException {
50 boolean done = false;
51 GpxData result = null;
52 String url = "trackpoints?bbox="+b.getMinLon()+','+b.getMinLat()+','+b.getMaxLon()+','+b.getMaxLat()+"&page=";
53 for (int i = 0; !done && !isCanceled(); ++i) {
54 progressMonitor.subTask(tr("Downloading points {0} to {1}...", i * 5000, (i + 1) * 5000));
55 try (InputStream in = getInputStream(url+i, progressMonitor.createSubTaskMonitor(1, true))) {
56 if (in == null) {
57 break;
58 }
59 progressMonitor.setTicks(0);
60 GpxReader reader = new GpxReader(in);
61 gpxParsedProperly = reader.parse(false);
62 GpxData currentGpx = reader.getGpxData();
63 if (result == null) {
64 result = currentGpx;
65 } else if (currentGpx.hasTrackPoints()) {
66 result.mergeFrom(currentGpx);
67 } else {
68 done = true;
69 }
70 } catch (OsmApiException ex) {
71 throw ex; // this avoids infinite loop in case of API error such as bad request (ex: bbox too large, see #12853)
72 } catch (OsmTransferException | SocketException ex) {
73 if (isCanceled()) {
74 final OsmTransferCanceledException canceledException = new OsmTransferCanceledException("Operation canceled");
75 canceledException.initCause(ex);
76 Main.warn(canceledException);
77 }
78 }
79 activeConnection = null;
80 }
81 if (result != null) {
82 result.fromServer = true;
83 result.dataSources.add(new DataSource(b, "OpenStreetMap server"));
84 }
85 return result;
86 }
87
88 @Override
89 public GpxData parseRawGps(ProgressMonitor progressMonitor) throws OsmTransferException {
90 progressMonitor.beginTask("", 1);
91 try {
92 progressMonitor.indeterminateSubTask(getTaskName());
93 if (crosses180th) {
94 // API 0.6 does not support requests crossing the 180th meridian, so make two requests
95 GpxData result = downloadRawGps(new Bounds(lat1, lon1, lat2, 180.0), progressMonitor);
96 if (result != null)
97 result.mergeFrom(downloadRawGps(new Bounds(lat1, -180.0, lat2, lon2), progressMonitor));
98 return result;
99 } else {
100 // Simple request
101 return downloadRawGps(new Bounds(lat1, lon1, lat2, lon2), progressMonitor);
102 }
103 } catch (IllegalArgumentException e) {
104 // caused by HttpUrlConnection in case of illegal stuff in the response
105 if (cancel)
106 return null;
107 throw new OsmTransferException("Illegal characters within the HTTP-header response.", e);
108 } catch (IOException e) {
109 if (cancel)
110 return null;
111 throw new OsmTransferException(e);
112 } catch (SAXException e) {
113 throw new OsmTransferException(e);
114 } catch (OsmTransferException e) {
115 throw e;
116 } catch (RuntimeException e) {
117 if (cancel)
118 return null;
119 throw e;
120 } finally {
121 progressMonitor.finishTask();
122 }
123 }
124
125 /**
126 * Returns the name of the download task to be displayed in the {@link ProgressMonitor}.
127 * @return task name
128 */
129 protected String getTaskName() {
130 return tr("Contacting OSM Server...");
131 }
132
133 /**
134 * Builds the request part for the bounding box.
135 * @param lon1 left
136 * @param lat1 bottom
137 * @param lon2 right
138 * @param lat2 top
139 * @return "map?bbox=left,bottom,right,top"
140 */
141 protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
142 return "map?bbox=" + lon1 + ',' + lat1 + ',' + lon2 + ',' + lat2;
143 }
144
145 /**
146 * Parse the given input source and return the dataset.
147 * @param source input stream
148 * @param progressMonitor progress monitor
149 * @return dataset
150 * @throws IllegalDataException if an error was found while parsing the OSM data
151 *
152 * @see OsmReader#parseDataSet(InputStream, ProgressMonitor)
153 */
154 protected DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
155 return OsmReader.parseDataSet(source, progressMonitor);
156 }
157
158 @Override
159 public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
160 progressMonitor.beginTask(getTaskName(), 10);
161 try {
162 DataSet ds = null;
163 progressMonitor.indeterminateSubTask(null);
164 if (crosses180th) {
165 // API 0.6 does not support requests crossing the 180th meridian, so make two requests
166 DataSet ds2 = null;
167
168 try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, 180.0, lat2),
169 progressMonitor.createSubTaskMonitor(9, false))) {
170 if (in == null)
171 return null;
172 ds = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
173 }
174
175 try (InputStream in = getInputStream(getRequestForBbox(-180.0, lat1, lon2, lat2),
176 progressMonitor.createSubTaskMonitor(9, false))) {
177 if (in == null)
178 return null;
179 ds2 = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
180 }
181 if (ds2 == null)
182 return null;
183 ds.mergeFrom(ds2);
184
185 } else {
186 // Simple request
187 try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, lon2, lat2),
188 progressMonitor.createSubTaskMonitor(9, false))) {
189 if (in == null)
190 return null;
191 ds = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
192 }
193 }
194 return ds;
195 } catch (OsmTransferException e) {
196 throw e;
197 } catch (IllegalDataException | IOException e) {
198 throw new OsmTransferException(e);
199 } finally {
200 progressMonitor.finishTask();
201 activeConnection = null;
202 }
203 }
204
205 @Override
206 public List<Note> parseNotes(int noteLimit, int daysClosed, ProgressMonitor progressMonitor) throws OsmTransferException {
207 progressMonitor.beginTask(tr("Downloading notes"));
208 CheckParameterUtil.ensureThat(noteLimit > 0, "Requested note limit is less than 1.");
209 // see result_limit in https://github.com/openstreetmap/openstreetmap-website/blob/master/app/controllers/notes_controller.rb
210 CheckParameterUtil.ensureThat(noteLimit <= 10_000, "Requested note limit is over API hard limit of 10000.");
211 CheckParameterUtil.ensureThat(daysClosed >= -1, "Requested note limit is less than -1.");
212 String url = "notes?limit=" + noteLimit + "&closed=" + daysClosed + "&bbox=" + lon1 + ',' + lat1 + ',' + lon2 + ',' + lat2;
213 try {
214 InputStream is = getInputStream(url, progressMonitor.createSubTaskMonitor(1, false));
215 NoteReader reader = new NoteReader(is);
216 final List<Note> notes = reader.parse();
217 if (notes.size() == noteLimit) {
218 throw new MoreNotesException(notes, noteLimit);
219 }
220 return notes;
221 } catch (IOException | SAXException e) {
222 throw new OsmTransferException(e);
223 } finally {
224 progressMonitor.finishTask();
225 }
226 }
227
228 /**
229 * Indicates that the number of fetched notes equals the specified limit. Thus there might be more notes to download.
230 */
231 public static class MoreNotesException extends RuntimeException {
232 /**
233 * The downloaded notes
234 */
235 public final transient List<Note> notes;
236 /**
237 * The download limit sent to the server.
238 */
239 public final int limit;
240
241 /**
242 * Constructs a {@code MoreNotesException}.
243 * @param notes downloaded notes
244 * @param limit download limit sent to the server
245 */
246 public MoreNotesException(List<Note> notes, int limit) {
247 this.notes = notes;
248 this.limit = limit;
249 }
250 }
251}
Note: See TracBrowser for help on using the repository browser.