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