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 }