source: josm/trunk/src/org/openstreetmap/josm/gui/io/UploadLayerTask.java@ 2569

Last change on this file since 2569 was 2569, checked in by Gubaer, 14 years ago

fixed #3684: Add "chunked" upload mode
Removed support for API "0.5" when uploading (there are still 0.5-files around, but I'm not aware of any 0.5-servers)

File size: 6.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Collection;
7import java.util.HashSet;
8
9import org.openstreetmap.josm.actions.upload.CyclicUploadDependencyException;
10import org.openstreetmap.josm.data.APIDataSet;
11import org.openstreetmap.josm.data.osm.Changeset;
12import org.openstreetmap.josm.data.osm.OsmPrimitive;
13import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
14import org.openstreetmap.josm.gui.DefaultNameFormatter;
15import org.openstreetmap.josm.gui.layer.OsmDataLayer;
16import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
17import org.openstreetmap.josm.gui.progress.ProgressMonitor;
18import org.openstreetmap.josm.io.OsmApi;
19import org.openstreetmap.josm.io.OsmApiPrimitiveGoneException;
20import org.openstreetmap.josm.io.OsmServerWriter;
21import org.openstreetmap.josm.io.OsmTransferException;
22
23/**
24 * UploadLayerTask uploads the data managed by an {@see OsmDataLayer} asynchronously.
25 *
26 * <pre>
27 * ExecutorService executorService = ...
28 * UploadLayerTask task = new UploadLayerTask(layer, monitor);
29 * Future<?> taskFuture = executorServce.submit(task)
30 * try {
31 * // wait for the task to complete
32 * taskFuture.get();
33 * } catch(Exception e) {
34 * e.printStackTracek();
35 * }
36 * </pre>
37 */
38class UploadLayerTask extends AbstractIOTask implements Runnable {
39 private OsmServerWriter writer;
40 private OsmDataLayer layer;
41 private ProgressMonitor monitor;
42 private Changeset changeset;
43 private boolean closeChangesetAfterUpload;
44 private Collection<OsmPrimitive> toUpload;
45 private HashSet<OsmPrimitive> processedPrimitives;
46 private UploadStrategySpecification strategy;
47
48 /**
49 * Creates the upload task
50 *
51 * @param strategy the upload strategy specification
52 * @param layer the layer. Must not be null.
53 * @param monitor a progress monitor. If monitor is null, uses {@see NullProgressMonitor#INSTANCE}
54 * @param changeset the changeset to be used
55 * @param closeChangesetAfterUpload true, if the changeset should be closed after the upload
56 * @throws IllegalArgumentException thrown, if layer is null
57 * @throws IllegalArgumentException thrown if strategy is null
58 */
59 public UploadLayerTask(UploadStrategySpecification strategy, OsmDataLayer layer, ProgressMonitor monitor, Changeset changeset, boolean closeChangesetAfterUpload) {
60 if (layer == null)
61 throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "layer"));
62 if (strategy == null)
63 throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "strategy"));
64 if (monitor == null) {
65 monitor = NullProgressMonitor.INSTANCE;
66 }
67 this.layer = layer;
68 this.monitor = monitor;
69 this.changeset = changeset;
70 this.strategy = strategy;
71 this.closeChangesetAfterUpload = closeChangesetAfterUpload;
72 processedPrimitives = new HashSet<OsmPrimitive>();
73 }
74
75 protected OsmPrimitive getPrimitive(OsmPrimitiveType type, long id) {
76 for (OsmPrimitive p: toUpload) {
77 if (OsmPrimitiveType.from(p).equals(type) && p.getId() == id)
78 return p;
79 }
80 return null;
81 }
82
83 /**
84 * Retries to recover the upload operation from an exception which was thrown because
85 * an uploaded primitive was already deleted on the server.
86 *
87 * @param e the exception throw by the API
88 * @param monitor a progress monitor
89 * @throws OsmTransferException thrown if we can't recover from the exception
90 */
91 protected void recoverFromGoneOnServer(OsmApiPrimitiveGoneException e, ProgressMonitor monitor) throws OsmTransferException{
92 if (!e.isKnownPrimitive()) throw e;
93 OsmPrimitive p = getPrimitive(e.getPrimitiveType(), e.getPrimitiveId());
94 if (p == null) throw e;
95 if (p.isDeleted()) {
96 // we tried to delete an already deleted primitive.
97 //
98 System.out.println(tr("Warning: primitive ''{0}'' is already deleted on the server. Skipping this primitive and retrying to upload.", p.getDisplayName(DefaultNameFormatter.getInstance())));
99 processedPrimitives.addAll(writer.getProcessedPrimitives());
100 processedPrimitives.add(p);
101 toUpload.removeAll(processedPrimitives);
102 return;
103 }
104 // exception was thrown because we tried to *update* an already deleted
105 // primitive. We can't resolve this automatically. Re-throw exception,
106 // a conflict is going to be created later.
107 throw e;
108 }
109
110 @Override
111 public void run() {
112 monitor.indeterminateSubTask(tr("Preparing primitives to upload ..."));
113 APIDataSet ds = new APIDataSet(layer.data);
114 try {
115 ds.adjustRelationUploadOrder();
116 } catch(CyclicUploadDependencyException e) {
117 setLastException(e);
118 return;
119 }
120 toUpload = ds.getPrimitives();
121 if (toUpload.isEmpty())
122 return;
123 writer = new OsmServerWriter();
124 try {
125 while(true) {
126 try {
127 ProgressMonitor m = monitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false);
128 if (isCancelled()) return;
129 writer.uploadOsm(strategy, toUpload, changeset, m);
130 processedPrimitives.addAll(writer.getProcessedPrimitives());
131 break;
132 } catch(OsmApiPrimitiveGoneException e) {
133 recoverFromGoneOnServer(e, monitor);
134 }
135 }
136 if (closeChangesetAfterUpload) {
137 if (changeset != null && changeset.getId() > 0) {
138 OsmApi.getOsmApi().closeChangeset(changeset, monitor.createSubTaskMonitor(0, false));
139 }
140 }
141 } catch (Exception sxe) {
142 if (isCancelled()) {
143 System.out.println("Ignoring exception caught because upload is cancelled. Exception is: " + sxe.toString());
144 return;
145 }
146 setLastException(sxe);
147 }
148
149 if (isCancelled())
150 return;
151 layer.cleanupAfterUpload(processedPrimitives);
152 layer.fireDataChange();
153 layer.onPostUploadToServer();
154
155 // don't process exceptions remembered with setLastException().
156 // Caller is supposed to deal with them.
157 }
158
159 @Override
160 public void cancel() {
161 setCancelled(true);
162 if (writer != null) {
163 writer.cancel();
164 }
165 }
166}
Note: See TracBrowser for help on using the repository browser.