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

Last change on this file since 11320 was 11100, checked in by Don-vip, 8 years ago

sonar - squid:S2148 - Underscores should be used to make large numbers readable

  • Property svn:eol-style set to native
File size: 9.9 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 result.mergeFrom(downloadRawGps(new Bounds(lat1, -180.0, lat2, lon2), progressMonitor));
97 return result;
98 } else {
99 // Simple request
100 return downloadRawGps(new Bounds(lat1, lon1, lat2, lon2), progressMonitor);
101 }
102 } catch (IllegalArgumentException e) {
103 // caused by HttpUrlConnection in case of illegal stuff in the response
104 if (cancel)
105 return null;
106 throw new OsmTransferException("Illegal characters within the HTTP-header response.", e);
107 } catch (IOException e) {
108 if (cancel)
109 return null;
110 throw new OsmTransferException(e);
111 } catch (SAXException e) {
112 throw new OsmTransferException(e);
113 } catch (OsmTransferException e) {
114 throw e;
115 } catch (RuntimeException e) {
116 if (cancel)
117 return null;
118 throw e;
119 } finally {
120 progressMonitor.finishTask();
121 }
122 }
123
124 /**
125 * Returns the name of the download task to be displayed in the {@link ProgressMonitor}.
126 * @return task name
127 */
128 protected String getTaskName() {
129 return tr("Contacting OSM Server...");
130 }
131
132 /**
133 * Builds the request part for the bounding box.
134 * @param lon1 left
135 * @param lat1 bottom
136 * @param lon2 right
137 * @param lat2 top
138 * @return "map?bbox=left,bottom,right,top"
139 */
140 protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
141 return "map?bbox=" + lon1 + ',' + lat1 + ',' + lon2 + ',' + lat2;
142 }
143
144 /**
145 * Parse the given input source and return the dataset.
146 * @param source input stream
147 * @param progressMonitor progress monitor
148 * @return dataset
149 * @throws IllegalDataException if an error was found while parsing the OSM data
150 *
151 * @see OsmReader#parseDataSet(InputStream, ProgressMonitor)
152 */
153 protected DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
154 return OsmReader.parseDataSet(source, progressMonitor);
155 }
156
157 @Override
158 public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
159 progressMonitor.beginTask(getTaskName(), 10);
160 try {
161 DataSet ds = null;
162 progressMonitor.indeterminateSubTask(null);
163 if (crosses180th) {
164 // API 0.6 does not support requests crossing the 180th meridian, so make two requests
165 DataSet ds2 = null;
166
167 try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, 180.0, lat2),
168 progressMonitor.createSubTaskMonitor(9, false))) {
169 if (in == null)
170 return null;
171 ds = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
172 }
173
174 try (InputStream in = getInputStream(getRequestForBbox(-180.0, lat1, lon2, lat2),
175 progressMonitor.createSubTaskMonitor(9, false))) {
176 if (in == null)
177 return null;
178 ds2 = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
179 }
180 if (ds2 == null)
181 return null;
182 ds.mergeFrom(ds2);
183
184 } else {
185 // Simple request
186 try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, lon2, lat2),
187 progressMonitor.createSubTaskMonitor(9, false))) {
188 if (in == null)
189 return null;
190 ds = parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
191 }
192 }
193 return ds;
194 } catch (OsmTransferException e) {
195 throw e;
196 } catch (IllegalDataException | IOException e) {
197 throw new OsmTransferException(e);
198 } finally {
199 progressMonitor.finishTask();
200 activeConnection = null;
201 }
202 }
203
204 @Override
205 public List<Note> parseNotes(int noteLimit, int daysClosed, ProgressMonitor progressMonitor) throws OsmTransferException {
206 progressMonitor.beginTask(tr("Downloading notes"));
207 CheckParameterUtil.ensureThat(noteLimit > 0, "Requested note limit is less than 1.");
208 // see result_limit in https://github.com/openstreetmap/openstreetmap-website/blob/master/app/controllers/notes_controller.rb
209 CheckParameterUtil.ensureThat(noteLimit <= 10_000, "Requested note limit is over API hard limit of 10000.");
210 CheckParameterUtil.ensureThat(daysClosed >= -1, "Requested note limit is less than -1.");
211 String url = "notes?limit=" + noteLimit + "&closed=" + daysClosed + "&bbox=" + lon1 + ',' + lat1 + ',' + lon2 + ',' + lat2;
212 try {
213 InputStream is = getInputStream(url, progressMonitor.createSubTaskMonitor(1, false));
214 NoteReader reader = new NoteReader(is);
215 final List<Note> notes = reader.parse();
216 if (notes.size() == noteLimit) {
217 throw new MoreNotesException(notes, noteLimit);
218 }
219 return notes;
220 } catch (IOException | SAXException e) {
221 throw new OsmTransferException(e);
222 } finally {
223 progressMonitor.finishTask();
224 }
225 }
226
227 /**
228 * Indicates that the number of fetched notes equals the specified limit. Thus there might be more notes to download.
229 */
230 public static class MoreNotesException extends RuntimeException {
231 /**
232 * The downloaded notes
233 */
234 public final transient List<Note> notes;
235 /**
236 * The download limit sent to the server.
237 */
238 public final int limit;
239
240 /**
241 * Constructs a {@code MoreNotesException}.
242 * @param notes downloaded notes
243 * @param limit download limit sent to the server
244 */
245 public MoreNotesException(List<Note> notes, int limit) {
246 this.notes = notes;
247 this.limit = limit;
248 }
249 }
250}
Note: See TracBrowser for help on using the repository browser.