001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.dialogs.relation; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.IOException; 007import java.lang.reflect.InvocationTargetException; 008import java.util.Collection; 009 010import javax.swing.SwingUtilities; 011 012import org.openstreetmap.josm.data.osm.DataSet; 013import org.openstreetmap.josm.data.osm.DataSetMerger; 014import org.openstreetmap.josm.data.osm.Relation; 015import org.openstreetmap.josm.gui.ExceptionDialogUtil; 016import org.openstreetmap.josm.gui.MainApplication; 017import org.openstreetmap.josm.gui.PleaseWaitRunnable; 018import org.openstreetmap.josm.gui.layer.OsmDataLayer; 019import org.openstreetmap.josm.gui.progress.ProgressMonitor; 020import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 021import org.openstreetmap.josm.io.OsmTransferException; 022import org.openstreetmap.josm.tools.CheckParameterUtil; 023import org.openstreetmap.josm.tools.Logging; 024import org.xml.sax.SAXException; 025 026/** 027 * The asynchronous task for fully downloading a collection of relations. Does a full download 028 * for each relations and merges the relation into an {@link OsmDataLayer} 029 * @since 2563 030 */ 031public class DownloadRelationTask extends PleaseWaitRunnable { 032 private boolean canceled; 033 private Exception lastException; 034 private final Collection<Relation> relations; 035 private final OsmDataLayer layer; 036 private MultiFetchServerObjectReader multiObjectReader; 037 038 /** 039 * Creates the download task 040 * 041 * @param relations a collection of relations. Must not be null. 042 * @param layer the layer which data is to be merged into 043 * @throws IllegalArgumentException if relations is null 044 * @throws IllegalArgumentException if layer is null 045 */ 046 public DownloadRelationTask(Collection<Relation> relations, OsmDataLayer layer) { 047 super(tr("Download relations"), false /* don't ignore exception */); 048 CheckParameterUtil.ensureParameterNotNull(relations, "relations"); 049 CheckParameterUtil.ensureParameterNotNull(layer, "layer"); 050 this.relations = relations; 051 this.layer = layer; 052 if (!layer.isDownloadable()) { 053 throw new IllegalArgumentException("Non-downloadable layer: " + layer); 054 } 055 } 056 057 @Override 058 protected void cancel() { 059 canceled = true; 060 synchronized (this) { 061 if (multiObjectReader != null) { 062 multiObjectReader.cancel(); 063 } 064 } 065 } 066 067 @Override 068 protected void finish() { 069 if (canceled) 070 return; 071 if (lastException != null) { 072 ExceptionDialogUtil.explainException(lastException); 073 } 074 } 075 076 @Override 077 protected void realRun() throws SAXException, IOException, OsmTransferException { 078 try { 079 final DataSet allDownloads = new DataSet(); 080 getProgressMonitor().setTicksCount(relations.size()); 081 DataSet dataSet = null; 082 synchronized (this) { 083 if (canceled) 084 return; 085 multiObjectReader = MultiFetchServerObjectReader.create(); 086 multiObjectReader.setRecurseDownRelations(true).setRecurseDownAppended(false); 087 multiObjectReader.append(relations); 088 dataSet = multiObjectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)); 089 } 090 if (dataSet == null) 091 return; 092 synchronized (this) { 093 if (canceled) 094 return; 095 } 096 new DataSetMerger(allDownloads, dataSet).merge(); 097 SwingUtilities.invokeAndWait(() -> { 098 layer.mergeFrom(allDownloads); 099 layer.onPostDownloadFromServer(); 100 MainApplication.getMap().repaint(); 101 }); 102 } catch (OsmTransferException | InvocationTargetException | InterruptedException e) { 103 if (canceled) { 104 Logging.warn(tr("Ignoring exception because task was canceled. Exception: {0}", e.toString())); 105 return; 106 } 107 lastException = e; 108 } 109 } 110}