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}