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.DefaultNameFormatter; 015import org.openstreetmap.josm.data.osm.Relation; 016import org.openstreetmap.josm.gui.ExceptionDialogUtil; 017import org.openstreetmap.josm.gui.MainApplication; 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.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 OsmServerObjectReader objectReader; 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 (objectReader != null) { 062 objectReader.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 int i = 0; 081 getProgressMonitor().setTicksCount(relations.size()); 082 for (Relation relation: relations) { 083 i++; 084 getProgressMonitor().setCustomText(tr("({0}/{1}): Downloading relation ''{2}''...", i, relations.size(), 085 relation.getDisplayName(DefaultNameFormatter.getInstance()))); 086 synchronized (this) { 087 if (canceled) return; 088 objectReader = new OsmServerObjectReader(relation.getPrimitiveId(), true /* full download */); 089 } 090 DataSet dataSet = objectReader.parseOsm( 091 getProgressMonitor().createSubTaskMonitor(0, false) 092 ); 093 if (dataSet == null) 094 return; 095 synchronized (this) { 096 if (canceled) return; 097 objectReader = null; 098 } 099 DataSetMerger merger = new DataSetMerger(allDownloads, dataSet); 100 merger.merge(); 101 getProgressMonitor().worked(1); 102 } 103 104 SwingUtilities.invokeAndWait(() -> { 105 layer.mergeFrom(allDownloads); 106 layer.onPostDownloadFromServer(); 107 MainApplication.getMap().repaint(); 108 }); 109 } catch (OsmTransferException | InvocationTargetException | InterruptedException e) { 110 if (canceled) { 111 Logging.warn(tr("Ignoring exception because task was canceled. Exception: {0}", e.toString())); 112 return; 113 } 114 lastException = e; 115 } 116 } 117}