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.Main; 013import org.openstreetmap.josm.data.osm.DataSet; 014import org.openstreetmap.josm.data.osm.DataSetMerger; 015import org.openstreetmap.josm.data.osm.Relation; 016import org.openstreetmap.josm.gui.DefaultNameFormatter; 017import org.openstreetmap.josm.gui.ExceptionDialogUtil; 018import org.openstreetmap.josm.gui.PleaseWaitRunnable; 019import org.openstreetmap.josm.gui.layer.OsmDataLayer; 020import org.openstreetmap.josm.io.OsmServerObjectReader; 021import org.openstreetmap.josm.io.OsmTransferException; 022import org.openstreetmap.josm.tools.CheckParameterUtil; 023import org.xml.sax.SAXException; 024 025/** 026 * The asynchronous task for fully downloading a collection of relations. Does a full download 027 * for each relations and merges the relation into an {@link OsmDataLayer} 028 * 029 */ 030public class DownloadRelationTask extends PleaseWaitRunnable { 031 private boolean canceled; 032 private Exception lastException; 033 private final Collection<Relation> relations; 034 private final OsmDataLayer layer; 035 private OsmServerObjectReader objectReader; 036 037 /** 038 * Creates the download task 039 * 040 * @param relations a collection of relations. Must not be null. 041 * @param layer the layer which data is to be merged into 042 * @throws IllegalArgumentException if relations is null 043 * @throws IllegalArgumentException if layer is null 044 */ 045 public DownloadRelationTask(Collection<Relation> relations, OsmDataLayer layer) { 046 super(tr("Download relations"), false /* don't ignore exception */); 047 CheckParameterUtil.ensureParameterNotNull(relations, "relations"); 048 CheckParameterUtil.ensureParameterNotNull(layer, "layer"); 049 this.relations = relations; 050 this.layer = layer; 051 } 052 053 @Override 054 protected void cancel() { 055 canceled = true; 056 synchronized (this) { 057 if (objectReader != null) { 058 objectReader.cancel(); 059 } 060 } 061 } 062 063 @Override 064 protected void finish() { 065 if (canceled) 066 return; 067 if (lastException != null) { 068 ExceptionDialogUtil.explainException(lastException); 069 } 070 } 071 072 @Override 073 protected void realRun() throws SAXException, IOException, OsmTransferException { 074 try { 075 final DataSet allDownloads = new DataSet(); 076 int i = 0; 077 getProgressMonitor().setTicksCount(relations.size()); 078 for (Relation relation: relations) { 079 i++; 080 getProgressMonitor().setCustomText(tr("({0}/{1}): Downloading relation ''{2}''...", i, relations.size(), 081 relation.getDisplayName(DefaultNameFormatter.getInstance()))); 082 synchronized (this) { 083 if (canceled) return; 084 objectReader = new OsmServerObjectReader(relation.getPrimitiveId(), true /* full download */); 085 } 086 DataSet dataSet = objectReader.parseOsm( 087 getProgressMonitor().createSubTaskMonitor(0, false) 088 ); 089 if (dataSet == null) 090 return; 091 synchronized (this) { 092 if (canceled) return; 093 objectReader = null; 094 } 095 DataSetMerger merger = new DataSetMerger(allDownloads, dataSet); 096 merger.merge(); 097 getProgressMonitor().worked(1); 098 } 099 100 SwingUtilities.invokeAndWait(() -> { 101 layer.mergeFrom(allDownloads); 102 layer.onPostDownloadFromServer(); 103 Main.map.repaint(); 104 }); 105 } catch (OsmTransferException | InvocationTargetException | InterruptedException e) { 106 if (canceled) { 107 Main.warn(tr("Ignoring exception because task was canceled. Exception: {0}", e.toString())); 108 return; 109 } 110 lastException = e; 111 } 112 } 113}