001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions.downloadtasks;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005import static org.openstreetmap.josm.tools.I18n.trn;
006
007import java.io.IOException;
008import java.net.URL;
009import java.util.List;
010import java.util.concurrent.Future;
011
012import javax.swing.JOptionPane;
013
014import org.openstreetmap.josm.Main;
015import org.openstreetmap.josm.data.Bounds;
016import org.openstreetmap.josm.data.notes.Note;
017import org.openstreetmap.josm.data.osm.NoteData;
018import org.openstreetmap.josm.data.preferences.IntegerProperty;
019import org.openstreetmap.josm.gui.PleaseWaitRunnable;
020import org.openstreetmap.josm.gui.layer.NoteLayer;
021import org.openstreetmap.josm.gui.progress.ProgressMonitor;
022import org.openstreetmap.josm.io.BoundingBoxDownloader;
023import org.openstreetmap.josm.io.BoundingBoxDownloader.MoreNotesException;
024import org.openstreetmap.josm.io.OsmApi;
025import org.openstreetmap.josm.io.OsmServerLocationReader;
026import org.openstreetmap.josm.io.OsmServerReader;
027import org.openstreetmap.josm.io.OsmTransferException;
028import org.xml.sax.SAXException;
029
030/** Task for downloading notes */
031public class DownloadNotesTask extends AbstractDownloadTask<NoteData> {
032
033    private static final String PATTERN_API_URL = "https?://.*/api/0.6/notes.*";
034    private static final String PATTERN_DUMP_FILE = "https?://.*/(.*\\.osn(.bz2)?)";
035    /** Property defining the number of notes to be downloaded */
036    public static final IntegerProperty DOWNLOAD_LIMIT = new IntegerProperty("osm.notes.downloadLimit", 1000);
037    /** Property defining number of days a bug needs to be closed to no longer be downloaded */
038    public static final IntegerProperty DAYS_CLOSED = new IntegerProperty("osm.notes.daysClosed", 7);
039
040    private DownloadTask downloadTask;
041
042    /**
043     * Download a specific note by its id.
044     * @param id Note identifier
045     * @param progressMonitor progress monitor
046     * @return the future representing the asynchronous task
047     */
048    public Future<?> download(long id, ProgressMonitor progressMonitor) {
049        final String url = OsmApi.getOsmApi().getBaseUrl() + "notes/" + id;
050        downloadTask = new DownloadRawUrlTask(new OsmServerLocationReader(url), progressMonitor);
051        return Main.worker.submit(downloadTask);
052    }
053
054    @Override
055    public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) {
056        downloadTask = new DownloadBoundingBoxTask(new BoundingBoxDownloader(downloadArea), progressMonitor);
057        return Main.worker.submit(downloadTask);
058    }
059
060    @Override
061    public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) {
062        if (url.endsWith(".bz2")) {
063            downloadTask = new DownloadBzip2RawUrlTask(new OsmServerLocationReader(url), progressMonitor);
064        } else {
065            downloadTask = new DownloadRawUrlTask(new OsmServerLocationReader(url), progressMonitor);
066        }
067        return Main.worker.submit(downloadTask);
068    }
069
070    @Override
071    public void cancel() {
072        if (downloadTask != null) {
073            downloadTask.cancel();
074        }
075    }
076
077    @Override
078    public String getConfirmationMessage(URL url) {
079        return null;
080    }
081
082    @Override
083    public String getTitle() {
084        return tr("Download OSM Notes");
085    }
086
087    @Override
088    public String[] getPatterns() {
089        return new String[] {PATTERN_API_URL, PATTERN_DUMP_FILE};
090    }
091
092    @Override
093    public boolean isSafeForRemotecontrolRequests() {
094        return true;
095    }
096
097    abstract class DownloadTask extends PleaseWaitRunnable {
098        protected OsmServerReader reader;
099        protected List<Note> notesData;
100
101        DownloadTask(OsmServerReader reader, ProgressMonitor progressMonitor) {
102            super(tr("Downloading Notes"), progressMonitor, false);
103            this.reader = reader;
104        }
105
106        @Override
107        protected void finish() {
108            rememberDownloadedData(new NoteData(notesData));
109            if (isCanceled() || isFailed() || notesData == null || notesData.isEmpty()) {
110                return;
111            }
112            if (Main.isDebugEnabled()) {
113                Main.debug("Notes downloaded: " + notesData.size());
114            }
115
116            List<NoteLayer> noteLayers = Main.getLayerManager().getLayersOfType(NoteLayer.class);
117            if (!noteLayers.isEmpty()) {
118                noteLayers.get(0).getNoteData().addNotes(notesData);
119            } else {
120                Main.getLayerManager().addLayer(new NoteLayer(notesData, tr("Notes")));
121            }
122        }
123
124        @Override
125        protected void cancel() {
126            setCanceled(true);
127            if (reader != null) {
128                reader.cancel();
129            }
130        }
131
132        @Override
133        public abstract void realRun() throws IOException, SAXException, OsmTransferException;
134    }
135
136    class DownloadBoundingBoxTask extends DownloadTask {
137
138        DownloadBoundingBoxTask(OsmServerReader reader, ProgressMonitor progressMonitor) {
139            super(reader, progressMonitor);
140        }
141
142        @Override
143        public void realRun() throws IOException, SAXException, OsmTransferException {
144            if (isCanceled()) {
145                return;
146            }
147            ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
148            try {
149                notesData = reader.parseNotes(DOWNLOAD_LIMIT.get(), DAYS_CLOSED.get(), subMonitor);
150            } catch (MoreNotesException e) {
151                Main.debug(e);
152                notesData = e.notes;
153                JOptionPane.showMessageDialog(Main.parent, "<html>"
154                                + trn("{0} note has been downloaded.", "{0} notes have been downloaded.", e.limit, e.limit)
155                                + "<br>"
156                                + tr("Since the download limit was {0}, there might be more notes to download.", e.limit)
157                                + "<br>"
158                                + tr("Request a smaller area to make sure that all notes are being downloaded.")
159                                + "</html>",
160                        tr("More notes to download"), JOptionPane.INFORMATION_MESSAGE);
161            } catch (OsmTransferException e) {
162                if (isCanceled())
163                    return;
164                rememberException(e);
165            }
166        }
167    }
168
169    class DownloadRawUrlTask extends DownloadTask {
170
171        DownloadRawUrlTask(OsmServerReader reader, ProgressMonitor progressMonitor) {
172            super(reader, progressMonitor);
173        }
174
175        @Override
176        public void realRun() throws IOException, SAXException, OsmTransferException {
177            if (isCanceled()) {
178                return;
179            }
180            ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
181            try {
182                notesData = reader.parseRawNotes(subMonitor);
183            } catch (OsmTransferException e) {
184                if (isCanceled())
185                    return;
186                rememberException(e);
187            }
188        }
189    }
190
191    class DownloadBzip2RawUrlTask extends DownloadTask {
192
193        DownloadBzip2RawUrlTask(OsmServerReader reader, ProgressMonitor progressMonitor) {
194            super(reader, progressMonitor);
195        }
196
197        @Override
198        public void realRun() throws IOException, SAXException, OsmTransferException {
199            if (isCanceled()) {
200                return;
201            }
202            ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
203            try {
204                notesData = reader.parseRawNotesBzip2(subMonitor);
205            } catch (OsmTransferException e) {
206                if (isCanceled())
207                    return;
208                rememberException(e);
209            }
210        }
211    }
212}