[6380] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
[444] | 2 | package org.openstreetmap.josm.io;
|
---|
| 3 |
|
---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
| 5 |
|
---|
| 6 | import java.io.IOException;
|
---|
| 7 | import java.io.InputStream;
|
---|
[7531] | 8 | import java.util.List;
|
---|
[444] | 9 |
|
---|
[2327] | 10 | import org.openstreetmap.josm.data.Bounds;
|
---|
[7575] | 11 | import org.openstreetmap.josm.data.DataSource;
|
---|
[1811] | 12 | import org.openstreetmap.josm.data.gpx.GpxData;
|
---|
[7531] | 13 | import org.openstreetmap.josm.data.notes.Note;
|
---|
[444] | 14 | import org.openstreetmap.josm.data.osm.DataSet;
|
---|
[1811] | 15 | import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
---|
[6474] | 16 | import org.openstreetmap.josm.tools.CheckParameterUtil;
|
---|
[444] | 17 | import org.xml.sax.SAXException;
|
---|
| 18 |
|
---|
[6244] | 19 | /**
|
---|
| 20 | * Read content from OSM server for a given bounding box
|
---|
| 21 | * @since 627
|
---|
| 22 | */
|
---|
[444] | 23 | public class BoundingBoxDownloader extends OsmServerReader {
|
---|
| 24 |
|
---|
[1169] | 25 | /**
|
---|
| 26 | * The boundings of the desired map data.
|
---|
| 27 | */
|
---|
[5097] | 28 | protected final double lat1;
|
---|
| 29 | protected final double lon1;
|
---|
| 30 | protected final double lat2;
|
---|
| 31 | protected final double lon2;
|
---|
| 32 | protected final boolean crosses180th;
|
---|
[444] | 33 |
|
---|
[6244] | 34 | /**
|
---|
| 35 | * Constructs a new {@code BoundingBoxDownloader}.
|
---|
| 36 | * @param downloadArea The area to download
|
---|
| 37 | */
|
---|
[2327] | 38 | public BoundingBoxDownloader(Bounds downloadArea) {
|
---|
[6474] | 39 | CheckParameterUtil.ensureParameterNotNull(downloadArea, "downloadArea");
|
---|
[6203] | 40 | this.lat1 = downloadArea.getMinLat();
|
---|
| 41 | this.lon1 = downloadArea.getMinLon();
|
---|
| 42 | this.lat2 = downloadArea.getMaxLat();
|
---|
| 43 | this.lon2 = downloadArea.getMaxLon();
|
---|
[4580] | 44 | this.crosses180th = downloadArea.crosses180thMeridian();
|
---|
[1169] | 45 | }
|
---|
[444] | 46 |
|
---|
[7575] | 47 | private GpxData downloadRawGps(Bounds b, ProgressMonitor progressMonitor) throws IOException, OsmTransferException, SAXException {
|
---|
[4580] | 48 | boolean done = false;
|
---|
| 49 | GpxData result = null;
|
---|
[7575] | 50 | String url = "trackpoints?bbox="+b.getMinLon()+","+b.getMinLat()+","+b.getMaxLon()+","+b.getMaxLat()+"&page=";
|
---|
[4580] | 51 | for (int i = 0;!done;++i) {
|
---|
| 52 | progressMonitor.subTask(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000)));
|
---|
[7033] | 53 | try (InputStream in = getInputStream(url+i, progressMonitor.createSubTaskMonitor(1, true))) {
|
---|
| 54 | if (in == null) {
|
---|
| 55 | break;
|
---|
| 56 | }
|
---|
| 57 | progressMonitor.setTicks(0);
|
---|
| 58 | GpxReader reader = new GpxReader(in);
|
---|
| 59 | gpxParsedProperly = reader.parse(false);
|
---|
| 60 | GpxData currentGpx = reader.getGpxData();
|
---|
| 61 | if (result == null) {
|
---|
| 62 | result = currentGpx;
|
---|
| 63 | } else if (currentGpx.hasTrackPoints()) {
|
---|
| 64 | result.mergeFrom(currentGpx);
|
---|
| 65 | } else{
|
---|
| 66 | done = true;
|
---|
| 67 | }
|
---|
[4580] | 68 | }
|
---|
| 69 | activeConnection = null;
|
---|
| 70 | }
|
---|
[7033] | 71 | if (result != null) {
|
---|
| 72 | result.fromServer = true;
|
---|
[7575] | 73 | result.dataSources.add(new DataSource(b, "OpenStreetMap server"));
|
---|
[7033] | 74 | }
|
---|
[4580] | 75 | return result;
|
---|
| 76 | }
|
---|
[6070] | 77 |
|
---|
[4521] | 78 | @Override
|
---|
| 79 | public GpxData parseRawGps(ProgressMonitor progressMonitor) throws OsmTransferException {
|
---|
[1811] | 80 | progressMonitor.beginTask("", 1);
|
---|
[1169] | 81 | try {
|
---|
[1811] | 82 | progressMonitor.indeterminateSubTask(tr("Contacting OSM Server..."));
|
---|
[4580] | 83 | if (crosses180th) {
|
---|
| 84 | // API 0.6 does not support requests crossing the 180th meridian, so make two requests
|
---|
[7575] | 85 | GpxData result = downloadRawGps(new Bounds(lat1, lon1, lat2, 180.0), progressMonitor);
|
---|
| 86 | result.mergeFrom(downloadRawGps(new Bounds(lat1, -180.0, lat2, lon2), progressMonitor));
|
---|
[4580] | 87 | return result;
|
---|
| 88 | } else {
|
---|
| 89 | // Simple request
|
---|
[7575] | 90 | return downloadRawGps(new Bounds(lat1, lon1, lat2, lon2), progressMonitor);
|
---|
[1169] | 91 | }
|
---|
| 92 | } catch (IllegalArgumentException e) {
|
---|
| 93 | // caused by HttpUrlConnection in case of illegal stuff in the response
|
---|
| 94 | if (cancel)
|
---|
| 95 | return null;
|
---|
[4521] | 96 | throw new OsmTransferException("Illegal characters within the HTTP-header response.", e);
|
---|
[1169] | 97 | } catch (IOException e) {
|
---|
| 98 | if (cancel)
|
---|
| 99 | return null;
|
---|
[4521] | 100 | throw new OsmTransferException(e);
|
---|
[1169] | 101 | } catch (SAXException e) {
|
---|
[4521] | 102 | throw new OsmTransferException(e);
|
---|
[1835] | 103 | } catch (OsmTransferException e) {
|
---|
| 104 | throw e;
|
---|
[2676] | 105 | } catch (RuntimeException e) {
|
---|
[1169] | 106 | if (cancel)
|
---|
| 107 | return null;
|
---|
[2676] | 108 | throw e;
|
---|
[1811] | 109 | } finally {
|
---|
| 110 | progressMonitor.finishTask();
|
---|
[1169] | 111 | }
|
---|
| 112 | }
|
---|
[444] | 113 |
|
---|
[5097] | 114 | protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
|
---|
| 115 | return "map?bbox=" + lon1 + "," + lat1 + "," + lon2 + "," + lat2;
|
---|
| 116 | }
|
---|
| 117 |
|
---|
[1670] | 118 | @Override
|
---|
[1811] | 119 | public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
|
---|
| 120 | progressMonitor.beginTask(tr("Contacting OSM Server..."), 10);
|
---|
[1169] | 121 | try {
|
---|
[4580] | 122 | DataSet ds = null;
|
---|
[1811] | 123 | progressMonitor.indeterminateSubTask(null);
|
---|
[4580] | 124 | if (crosses180th) {
|
---|
| 125 | // API 0.6 does not support requests crossing the 180th meridian, so make two requests
|
---|
[7033] | 126 | DataSet ds2 = null;
|
---|
[4580] | 127 |
|
---|
[7033] | 128 | try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, 180.0, lat2), progressMonitor.createSubTaskMonitor(9, false))) {
|
---|
| 129 | if (in == null)
|
---|
| 130 | return null;
|
---|
| 131 | ds = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | try (InputStream in = getInputStream(getRequestForBbox(-180.0, lat1, lon2, lat2), progressMonitor.createSubTaskMonitor(9, false))) {
|
---|
| 135 | if (in == null)
|
---|
| 136 | return null;
|
---|
| 137 | ds2 = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
|
---|
| 138 | }
|
---|
[4580] | 139 | if (ds2 == null)
|
---|
| 140 | return null;
|
---|
| 141 | ds.mergeFrom(ds2);
|
---|
[6070] | 142 |
|
---|
[4580] | 143 | } else {
|
---|
| 144 | // Simple request
|
---|
[7033] | 145 | try (InputStream in = getInputStream(getRequestForBbox(lon1, lat1, lon2, lat2), progressMonitor.createSubTaskMonitor(9, false))) {
|
---|
| 146 | if (in == null)
|
---|
| 147 | return null;
|
---|
| 148 | ds = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
|
---|
| 149 | }
|
---|
[4580] | 150 | }
|
---|
| 151 | return ds;
|
---|
[1670] | 152 | } catch(OsmTransferException e) {
|
---|
[1169] | 153 | throw e;
|
---|
| 154 | } catch (Exception e) {
|
---|
[1670] | 155 | throw new OsmTransferException(e);
|
---|
[1811] | 156 | } finally {
|
---|
| 157 | progressMonitor.finishTask();
|
---|
[1879] | 158 | activeConnection = null;
|
---|
[1169] | 159 | }
|
---|
| 160 | }
|
---|
[7531] | 161 |
|
---|
| 162 | @Override
|
---|
[8218] | 163 | public List<Note> parseNotes(int noteLimit, int daysClosed, ProgressMonitor progressMonitor) throws OsmTransferException, MoreNotesException {
|
---|
[7531] | 164 | progressMonitor.beginTask("Downloading notes");
|
---|
[8218] | 165 | CheckParameterUtil.ensureThat(noteLimit > 0, "Requested note limit is less than 1.");
|
---|
[8230] | 166 | // see result_limit in https://github.com/openstreetmap/openstreetmap-website/blob/master/app/controllers/notes_controller.rb
|
---|
| 167 | CheckParameterUtil.ensureThat(noteLimit <= 10000, "Requested note limit is over API hard limit of 10000.");
|
---|
[8218] | 168 | CheckParameterUtil.ensureThat(daysClosed >= 0, "Requested note limit is less than 0.");
|
---|
| 169 | String url = "notes?limit=" + noteLimit + "&closed=" + daysClosed + "&bbox=" + lon1 + "," + lat1 + "," + lon2 + "," + lat2;
|
---|
[7531] | 170 | try {
|
---|
| 171 | InputStream is = getInputStream(url, progressMonitor.createSubTaskMonitor(1, false));
|
---|
| 172 | NoteReader reader = new NoteReader(is);
|
---|
[8216] | 173 | final List<Note> notes = reader.parse();
|
---|
| 174 | if (notes.size() == noteLimit) {
|
---|
[8217] | 175 | throw new MoreNotesException(notes, noteLimit);
|
---|
[8216] | 176 | }
|
---|
| 177 | return notes;
|
---|
[7531] | 178 | } catch (IOException e) {
|
---|
| 179 | throw new OsmTransferException(e);
|
---|
| 180 | } catch (SAXException e) {
|
---|
| 181 | throw new OsmTransferException(e);
|
---|
| 182 | } finally {
|
---|
| 183 | progressMonitor.finishTask();
|
---|
| 184 | }
|
---|
| 185 | }
|
---|
| 186 |
|
---|
[8216] | 187 | /**
|
---|
| 188 | * Indicates that the number of fetched notes equals the specified limit. Thus there might be more notes to download.
|
---|
| 189 | */
|
---|
| 190 | public static class MoreNotesException extends RuntimeException{
|
---|
| 191 | /**
|
---|
[8217] | 192 | * The downloaded notes
|
---|
| 193 | */
|
---|
[8308] | 194 | public final transient List<Note> notes;
|
---|
[8217] | 195 | /**
|
---|
[8216] | 196 | * The download limit sent to the server.
|
---|
| 197 | */
|
---|
| 198 | public final int limit;
|
---|
| 199 |
|
---|
[8217] | 200 | public MoreNotesException(List<Note> notes, int limit) {
|
---|
| 201 | this.notes = notes;
|
---|
[8216] | 202 | this.limit = limit;
|
---|
| 203 | }
|
---|
| 204 | }
|
---|
| 205 |
|
---|
[444] | 206 | }
|
---|