001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.io; 003 004 import static org.openstreetmap.josm.tools.CheckParameterUtil.ensureParameterNotNull; 005 import static org.openstreetmap.josm.tools.I18n.tr; 006 007 import java.io.IOException; 008 import java.lang.reflect.InvocationTargetException; 009 import java.util.Collection; 010 import java.util.Collections; 011 012 import javax.swing.SwingUtilities; 013 014 import org.openstreetmap.josm.data.osm.DataSet; 015 import org.openstreetmap.josm.data.osm.DataSetMerger; 016 import org.openstreetmap.josm.data.osm.Node; 017 import org.openstreetmap.josm.data.osm.OsmPrimitive; 018 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 019 import org.openstreetmap.josm.data.osm.Relation; 020 import org.openstreetmap.josm.data.osm.Way; 021 import org.openstreetmap.josm.gui.ExceptionDialogUtil; 022 import org.openstreetmap.josm.gui.PleaseWaitRunnable; 023 import org.openstreetmap.josm.gui.layer.OsmDataLayer; 024 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 025 import org.openstreetmap.josm.gui.util.GuiHelper; 026 import org.openstreetmap.josm.io.MultiFetchServerObjectReader; 027 import org.openstreetmap.josm.io.OsmServerObjectReader; 028 import org.openstreetmap.josm.io.OsmTransferException; 029 import org.xml.sax.SAXException; 030 031 /** 032 * The asynchronous task for updating a collection of objects using multi fetch. 033 * 034 */ 035 public class UpdatePrimitivesTask extends PleaseWaitRunnable { 036 private DataSet ds; 037 private boolean canceled; 038 private Exception lastException; 039 private Collection<? extends OsmPrimitive> toUpdate; 040 private OsmDataLayer layer; 041 private MultiFetchServerObjectReader multiObjectReader; 042 private OsmServerObjectReader objectReader; 043 044 /** 045 * Creates the task 046 * 047 * @param layer the layer in which primitives are updated. Must not be null. 048 * @param toUpdate a collection of primitives to update from the server. Set to 049 * the empty collection if null. 050 * @throws IllegalArgumentException thrown if layer is null. 051 */ 052 public UpdatePrimitivesTask(OsmDataLayer layer, Collection<? extends OsmPrimitive> toUpdate) throws IllegalArgumentException{ 053 super(tr("Update objects"), false /* don't ignore exception */); 054 ensureParameterNotNull(layer, "layer"); 055 if (toUpdate == null) { 056 toUpdate = Collections.emptyList(); 057 } 058 this.layer = layer; 059 this.toUpdate = toUpdate; 060 } 061 062 @Override 063 protected void cancel() { 064 canceled = true; 065 synchronized(this) { 066 if (multiObjectReader != null) { 067 multiObjectReader.cancel(); 068 } 069 if (objectReader != null) { 070 objectReader.cancel(); 071 } 072 } 073 } 074 075 @Override 076 protected void finish() { 077 if (canceled) 078 return; 079 if (lastException != null) { 080 ExceptionDialogUtil.explainException(lastException); 081 return; 082 } 083 GuiHelper.runInEDTAndWait(new Runnable() { 084 public void run() { 085 layer.mergeFrom(ds); 086 layer.onPostDownloadFromServer(); 087 } 088 }); 089 } 090 091 protected void initMultiFetchReaderWithNodes(MultiFetchServerObjectReader reader) { 092 getProgressMonitor().indeterminateSubTask(tr("Initializing nodes to update ...")); 093 for (OsmPrimitive primitive : toUpdate) { 094 if (primitive instanceof Node && !primitive.isNew()) { 095 reader.append((Node)primitive); 096 } else if (primitive instanceof Way) { 097 Way way = (Way)primitive; 098 for (Node node: way.getNodes()) { 099 if (!node.isNew()) { 100 reader.append(node); 101 } 102 } 103 } 104 } 105 } 106 107 protected void initMultiFetchReaderWithWays(MultiFetchServerObjectReader reader) { 108 getProgressMonitor().indeterminateSubTask(tr("Initializing ways to update ...")); 109 for (OsmPrimitive primitive : toUpdate) { 110 if (primitive instanceof Way && !primitive.isNew()) { 111 reader.append((Way)primitive); 112 } 113 } 114 } 115 116 protected void initMultiFetchReaderWithRelations(MultiFetchServerObjectReader reader) { 117 getProgressMonitor().indeterminateSubTask(tr("Initializing relations to update ...")); 118 for (OsmPrimitive primitive : toUpdate) { 119 if (primitive instanceof Relation && !primitive.isNew()) { 120 reader.append((Relation)primitive); 121 } 122 } 123 } 124 125 @Override 126 protected void realRun() throws SAXException, IOException, OsmTransferException { 127 this.ds = new DataSet(); 128 DataSet theirDataSet; 129 try { 130 synchronized(this) { 131 if (canceled) return; 132 multiObjectReader = new MultiFetchServerObjectReader(); 133 } 134 initMultiFetchReaderWithNodes(multiObjectReader); 135 initMultiFetchReaderWithWays(multiObjectReader); 136 initMultiFetchReaderWithRelations(multiObjectReader); 137 theirDataSet = multiObjectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)); 138 synchronized(this) { 139 multiObjectReader = null; 140 } 141 DataSetMerger merger = new DataSetMerger(ds, theirDataSet); 142 merger.merge(); 143 // a way loaded with MultiFetch may have incomplete nodes because at least one of its 144 // nodes isn't present in the local data set. We therefore fully load all 145 // ways with incomplete nodes. 146 // 147 for (Way w : ds.getWays()) { 148 if (canceled) return; 149 if (w.hasIncompleteNodes()) { 150 synchronized(this) { 151 if (canceled) return; 152 objectReader = new OsmServerObjectReader(w.getId(), OsmPrimitiveType.WAY, true /* full */); 153 } 154 theirDataSet = objectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)); 155 synchronized (this) { 156 objectReader = null; 157 } 158 merger = new DataSetMerger(ds, theirDataSet); 159 merger.merge(); 160 } 161 } 162 } catch(Exception e) { 163 if (canceled) 164 return; 165 lastException = e; 166 } 167 } 168 }