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

Last change on this file since 9705 was 9509, checked in by simon04, 8 years ago

fix #9925 - Allow to stop downloading GPS data and keep the downloaded part

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