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()) { 109 return; 110 } 111 112 if (notesData == null) { 113 return; 114 } 115 if (Main.isDebugEnabled()) { 116 Main.debug("Notes downloaded: " + notesData.size()); 117 } 118 119 List<NoteLayer> noteLayers = null; 120 if (Main.map != null) { 121 noteLayers = Main.map.mapView.getLayersOfType(NoteLayer.class); 122 } 123 NoteLayer layer; 124 if (noteLayers != null && !noteLayers.isEmpty()) { 125 layer = noteLayers.get(0); 126 layer.getNoteData().addNotes(notesData); 127 } else { 128 layer = new NoteLayer(notesData, tr("Notes")); 129 Main.main.addLayer(layer); 130 } 131 } 132 133 @Override 134 protected void cancel() { 135 setCanceled(true); 136 if (reader != null) { 137 reader.cancel(); 138 } 139 } 140 141 @Override 142 public abstract void realRun() throws IOException, SAXException, OsmTransferException; 143 } 144 145 class DownloadBoundingBoxTask extends DownloadTask { 146 147 DownloadBoundingBoxTask(OsmServerReader reader, ProgressMonitor progressMonitor) { 148 super(reader, progressMonitor); 149 } 150 151 @Override 152 public void realRun() throws IOException, SAXException, OsmTransferException { 153 if (isCanceled()) { 154 return; 155 } 156 ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); 157 try { 158 notesData = reader.parseNotes(DOWNLOAD_LIMIT.get(), DAYS_CLOSED.get(), subMonitor); 159 } catch (BoundingBoxDownloader.MoreNotesException e) { 160 notesData = e.notes; 161 JOptionPane.showMessageDialog(Main.parent, "<html>" 162 + trn("{0} note has been downloaded.", "{0} notes have been downloaded.", e.limit, e.limit) 163 + "<br>" 164 + tr("Since the download limit was {0}, there might be more notes to download.", e.limit) 165 + "<br>" 166 + tr("Request a smaller area to make sure that all notes are being downloaded.") 167 + "</html>", 168 tr("More notes to download"), JOptionPane.INFORMATION_MESSAGE); 169 } catch (Exception e) { 170 if (isCanceled()) 171 return; 172 if (e instanceof OsmTransferException) { 173 rememberException(e); 174 } else { 175 rememberException(new OsmTransferException(e)); 176 } 177 } 178 } 179 } 180 181 class DownloadRawUrlTask extends DownloadTask { 182 183 DownloadRawUrlTask(OsmServerReader reader, ProgressMonitor progressMonitor) { 184 super(reader, progressMonitor); 185 } 186 187 @Override 188 public void realRun() throws IOException, SAXException, OsmTransferException { 189 if (isCanceled()) { 190 return; 191 } 192 ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); 193 try { 194 notesData = reader.parseRawNotes(subMonitor); 195 } catch (Exception e) { 196 if (isCanceled()) 197 return; 198 if (e instanceof OsmTransferException) { 199 rememberException(e); 200 } else { 201 rememberException(new OsmTransferException(e)); 202 } 203 } 204 } 205 } 206 207 class DownloadBzip2RawUrlTask extends DownloadTask { 208 209 DownloadBzip2RawUrlTask(OsmServerReader reader, ProgressMonitor progressMonitor) { 210 super(reader, progressMonitor); 211 } 212 213 @Override 214 public void realRun() throws IOException, SAXException, OsmTransferException { 215 if (isCanceled()) { 216 return; 217 } 218 ProgressMonitor subMonitor = progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false); 219 try { 220 notesData = reader.parseRawNotesBzip2(subMonitor); 221 } catch (Exception e) { 222 if (isCanceled()) 223 return; 224 if (e instanceof OsmTransferException) { 225 rememberException(e); 226 } else { 227 rememberException(new OsmTransferException(e)); 228 } 229 } 230 } 231 } 232}