source: josm/trunk/src/org/openstreetmap/josm/actions/UploadAction.java@ 2550

Last change on this file since 2550 was 2512, checked in by stoecker, 14 years ago

i18n updated, fixed files to reduce problems when applying patches, fix #4017

  • Property svn:eol-style set to native
File size: 27.1 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.io.IOException;
10import java.net.HttpURLConnection;
11import java.text.SimpleDateFormat;
12import java.util.Collection;
13import java.util.Date;
14import java.util.HashSet;
15import java.util.LinkedList;
16import java.util.logging.Logger;
17import java.util.regex.Matcher;
18import java.util.regex.Pattern;
19
20import javax.swing.JOptionPane;
21
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.actions.upload.ApiPreconditionCheckerHook;
24import org.openstreetmap.josm.actions.upload.RelationUploadOrderHook;
25import org.openstreetmap.josm.actions.upload.UploadHook;
26import org.openstreetmap.josm.actions.upload.UploadParameterHook;
27import org.openstreetmap.josm.data.APIDataSet;
28import org.openstreetmap.josm.data.conflict.ConflictCollection;
29import org.openstreetmap.josm.data.osm.Changeset;
30import org.openstreetmap.josm.data.osm.OsmPrimitive;
31import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
32import org.openstreetmap.josm.gui.DefaultNameFormatter;
33import org.openstreetmap.josm.gui.ExceptionDialogUtil;
34import org.openstreetmap.josm.gui.HelpAwareOptionPane;
35import org.openstreetmap.josm.gui.PleaseWaitRunnable;
36import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
37import org.openstreetmap.josm.gui.io.UploadDialog;
38import org.openstreetmap.josm.gui.layer.OsmDataLayer;
39import org.openstreetmap.josm.gui.progress.ProgressMonitor;
40import org.openstreetmap.josm.io.ChangesetClosedException;
41import org.openstreetmap.josm.io.OsmApi;
42import org.openstreetmap.josm.io.OsmApiException;
43import org.openstreetmap.josm.io.OsmApiInitializationException;
44import org.openstreetmap.josm.io.OsmApiPrimitiveGoneException;
45import org.openstreetmap.josm.io.OsmServerWriter;
46import org.openstreetmap.josm.io.OsmTransferException;
47import org.openstreetmap.josm.tools.DateUtils;
48import org.openstreetmap.josm.tools.ImageProvider;
49import org.openstreetmap.josm.tools.Shortcut;
50import org.xml.sax.SAXException;
51
52/**
53 * Action that opens a connection to the osm server and uploads all changes.
54 *
55 * An dialog is displayed asking the user to specify a rectangle to grab.
56 * The url and account settings from the preferences are used.
57 *
58 * If the upload fails this action offers various options to resolve conflicts.
59 *
60 * @author imi
61 */
62public class UploadAction extends JosmAction{
63 static private Logger logger = Logger.getLogger(UploadAction.class.getName());
64 /**
65 * The list of upload hooks. These hooks will be called one after the other
66 * when the user wants to upload data. Plugins can insert their own hooks here
67 * if they want to be able to veto an upload.
68 *
69 * Be default, the standard upload dialog is the only element in the list.
70 * Plugins should normally insert their code before that, so that the upload
71 * dialog is the last thing shown before upload really starts; on occasion
72 * however, a plugin might also want to insert something after that.
73 */
74 private static final LinkedList<UploadHook> uploadHooks = new LinkedList<UploadHook>();
75 static {
76 /**
77 * Checks server capabilities before upload.
78 */
79 uploadHooks.add(new ApiPreconditionCheckerHook());
80
81 /**
82 * Adjusts the upload order of new relations
83 */
84 uploadHooks.add(new RelationUploadOrderHook());
85
86 /**
87 * Displays a screen where the actions that would be taken are displayed and
88 * give the user the possibility to cancel the upload.
89 */
90 uploadHooks.add(new UploadParameterHook());
91 }
92
93 /**
94 * Registers an upload hook. Adds the hook at the first position of the upload hooks.
95 *
96 * @param hook the upload hook. Ignored if null.
97 */
98 public static void registerUploadHook(UploadHook hook) {
99 if(hook == null) return;
100 if (!uploadHooks.contains(hook)) {
101 uploadHooks.add(0,hook);
102 }
103 }
104
105 /**
106 * Unregisters an upload hook. Removes the hook from the list of upload hooks.
107 *
108 * @param hook the upload hook. Ignored if null.
109 */
110 public static void unregisterUploadHook(UploadHook hook) {
111 if(hook == null) return;
112 if (uploadHooks.contains(hook)) {
113 uploadHooks.remove(hook);
114 }
115 }
116
117 public UploadAction() {
118 super(tr("Upload data"), "upload", tr("Upload all changes in the active data layer to the OSM server"),
119 Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload data")), KeyEvent.VK_U, Shortcut.GROUPS_ALT1+Shortcut.GROUP_HOTKEY), true);
120 putValue("help", ht("/Action/Upload"));
121 }
122
123 /**
124 * Refreshes the enabled state
125 *
126 */
127 @Override
128 protected void updateEnabledState() {
129 setEnabled(getEditLayer() != null);
130 }
131
132 public boolean checkPreUploadConditions(OsmDataLayer layer) {
133 return checkPreUploadConditions(layer, new APIDataSet(layer.data));
134 }
135
136 public boolean checkPreUploadConditions(OsmDataLayer layer, APIDataSet apiData) {
137 ConflictCollection conflicts = layer.getConflicts();
138 if (conflicts !=null && !conflicts.isEmpty()) {
139 JOptionPane.showMessageDialog(
140 Main.parent,
141 tr("<html>There are unresolved conflicts in layer ''{0}''.<br>"
142 + "You have to resolve them first.</html>", layer.getName()),
143 tr("Warning"),
144 JOptionPane.WARNING_MESSAGE
145 );
146 return false;
147 }
148 // Call all upload hooks in sequence. The upload confirmation dialog
149 // is one of these.
150 for(UploadHook hook : uploadHooks)
151 if(!hook.checkUpload(apiData))
152 return false;
153
154 return true;
155 }
156
157 public void uploadData(OsmDataLayer layer, APIDataSet apiData) {
158 if (apiData.isEmpty()) {
159 JOptionPane.showMessageDialog(
160 Main.parent,
161 tr("No changes to upload."),
162 tr("Warning"),
163 JOptionPane.INFORMATION_MESSAGE
164 );
165 return;
166 }
167 if (!checkPreUploadConditions(layer, apiData))
168 return;
169 Main.worker.execute(
170 createUploadTask(
171 layer,
172 apiData.getPrimitives(),
173 UploadDialog.getUploadDialog().getChangeset(),
174 UploadDialog.getUploadDialog().isDoCloseAfterUpload()
175 )
176 );
177 }
178
179 public void actionPerformed(ActionEvent e) {
180 if (!isEnabled())
181 return;
182 if (Main.map == null) {
183 JOptionPane.showMessageDialog(
184 Main.parent,
185 tr("Nothing to upload. Get some data first."),
186 tr("Warning"),
187 JOptionPane.WARNING_MESSAGE
188 );
189 return;
190 }
191 APIDataSet apiData = new APIDataSet(Main.main.getCurrentDataSet());
192 uploadData(Main.map.mapView.getEditLayer(), apiData);
193 }
194
195 /**
196 * Synchronizes the local state of an {@see OsmPrimitive} with its state on the
197 * server. The method uses an individual GET for the primitive.
198 *
199 * @param id the primitive ID
200 */
201 protected void synchronizePrimitive(final OsmPrimitiveType type, final long id) {
202 Main.worker.execute(new UpdatePrimitiveTask(type, id));
203 }
204
205 /**
206 * Synchronizes the local state of the dataset with the state on the server.
207 *
208 * Reuses the functionality of {@see UpdateDataAction}.
209 *
210 * @see UpdateDataAction#actionPerformed(ActionEvent)
211 */
212 protected void synchronizeDataSet() {
213 UpdateDataAction act = new UpdateDataAction();
214 act.actionPerformed(new ActionEvent(this,0,""));
215 }
216
217 /**
218 * Handles the case that a conflict in a specific {@see OsmPrimitive} was detected while
219 * uploading
220 *
221 * @param primitiveType the type of the primitive, either <code>node</code>, <code>way</code> or
222 * <code>relation</code>
223 * @param id the id of the primitive
224 * @param serverVersion the version of the primitive on the server
225 * @param myVersion the version of the primitive in the local dataset
226 */
227 protected void handleUploadConflictForKnownConflict(final OsmPrimitiveType primitiveType, final long id, String serverVersion, String myVersion) {
228 String lbl = "";
229 switch(primitiveType) {
230 case NODE: lbl = tr("Synchronize node {0} only", id); break;
231 case WAY: lbl = tr("Synchronize way {0} only", id); break;
232 case RELATION: lbl = tr("Synchronize relation {0} only", id); break;
233 }
234 ButtonSpec[] spec = new ButtonSpec[] {
235 new ButtonSpec(
236 lbl,
237 ImageProvider.get("updatedata"),
238 null,
239 null
240 ),
241 new ButtonSpec(
242 tr("Synchronize entire dataset"),
243 ImageProvider.get("updatedata"),
244 null,
245 null
246 ),
247 new ButtonSpec(
248 tr("Cancel"),
249 ImageProvider.get("cancel"),
250 null,
251 null
252 )
253 };
254 String msg = tr("<html>Uploading <strong>failed</strong> because the server has a newer version of one<br>"
255 + "of your nodes, ways, or relations.<br>"
256 + "The conflict is caused by the <strong>{0}</strong> with id <strong>{1}</strong>,<br>"
257 + "the server has version {2}, your version is {3}.<br>"
258 + "<br>"
259 + "Click <strong>{4}</strong> to synchronize the conflicting primitive only.<br>"
260 + "Click <strong>{5}</strong> to synchronize the entire local dataset with the server.<br>"
261 + "Click <strong>{6}</strong> to abort and continue editing.<br></html>",
262 tr(primitiveType.getAPIName()), id, serverVersion, myVersion,
263 spec[0].text, spec[1].text, spec[2].text
264 );
265 int ret = HelpAwareOptionPane.showOptionDialog(
266 Main.parent,
267 msg,
268 tr("Conflicts detected"),
269 JOptionPane.ERROR_MESSAGE,
270 null,
271 spec,
272 spec[0],
273 "/Concepts/Conflict"
274 );
275 switch(ret) {
276 case 0: synchronizePrimitive(primitiveType, id); break;
277 case 1: synchronizeDataSet(); break;
278 default: return;
279 }
280 }
281
282 /**
283 * Handles the case that a conflict was detected while uploading where we don't
284 * know what {@see OsmPrimitive} actually caused the conflict (for whatever reason)
285 *
286 */
287 protected void handleUploadConflictForUnknownConflict() {
288 ButtonSpec[] spec = new ButtonSpec[] {
289 new ButtonSpec(
290 tr("Synchronize entire dataset"),
291 ImageProvider.get("updatedata"),
292 null,
293 null
294 ),
295 new ButtonSpec(
296 tr("Cancel"),
297 ImageProvider.get("cancel"),
298 null,
299 null
300 )
301 };
302 String msg = tr("<html>Uploading <strong>failed</strong> because the server has a newer version of one<br>"
303 + "of your nodes, ways, or relations.<br>"
304 + "<br>"
305 + "Click <strong>{0}</strong> to synchronize the entire local dataset with the server.<br>"
306 + "Click <strong>{1}</strong> to abort and continue editing.<br></html>",
307 spec[0].text, spec[1].text
308 );
309 int ret = HelpAwareOptionPane.showOptionDialog(
310 Main.parent,
311 msg,
312 tr("Conflicts detected"),
313 JOptionPane.ERROR_MESSAGE,
314 null,
315 spec,
316 spec[0],
317 "Concepts/Conflict"
318 );
319 if (ret == 0) {
320 synchronizeDataSet();
321 }
322 }
323
324 /**
325 * Handles the case that a conflict was detected while uploading where we don't
326 * know what {@see OsmPrimitive} actually caused the conflict (for whatever reason)
327 *
328 */
329 protected void handleUploadConflictForClosedChangeset(long changsetId, Date d) {
330 String msg = tr("<html>Uploading <strong>failed</strong> because you''ve been using<br>"
331 + "changeset {0} which was already closed at {1}.<br>"
332 + "Please upload again with a new or an existing open changeset.</html>",
333 changsetId, new SimpleDateFormat().format(d)
334 );
335 JOptionPane.showMessageDialog(
336 Main.parent,
337 msg,
338 tr("Changeset closed"),
339 JOptionPane.ERROR_MESSAGE
340 );
341 }
342
343 /**
344 * Handles the case where deleting a node failed because it is still in use in
345 * a non-deleted way on the server.
346 */
347 protected void handleUploadConflictForNodeStillInUse(long nodeId, long wayId) {
348 ButtonSpec[] options = new ButtonSpec[] {
349 new ButtonSpec(
350 tr("Prepare conflict resolution"),
351 ImageProvider.get("ok"),
352 tr("Click to download all parent ways for node {0}", nodeId),
353 null /* no specific help context */
354 ),
355 new ButtonSpec(
356 tr("Cancel"),
357 ImageProvider.get("cancel"),
358 tr("Click to cancel and to resume editing the map", nodeId),
359 null /* no specific help context */
360 )
361 };
362 String msg = tr("<html>Uploading <strong>failed</strong> because you tried "
363 + "to delete node {0} which is still in use in way {1}.<br><br>"
364 + "Click <strong>{2}</strong> to download all parent ways of node {0}.<br>"
365 + "If necessary JOSM will create conflicts which you can resolve in the Conflict Resolution Dialog."
366 + "</html>",
367 nodeId, wayId, options[0].text
368 );
369
370 int ret = HelpAwareOptionPane.showOptionDialog(
371 Main.parent,
372 msg,
373 tr("Node still in use"),
374 JOptionPane.ERROR_MESSAGE,
375 null,
376 options,
377 options[0],
378 "/Action/Upload#NodeStillInUseInWay"
379 );
380 if (ret != 0) return;
381 DownloadReferrersAction.downloadReferrers(Main.map.mapView.getEditLayer(), nodeId, OsmPrimitiveType.NODE);
382 }
383
384 /**
385 * handles an upload conflict, i.e. an error indicated by a HTTP return code 409.
386 *
387 * @param e the exception
388 */
389 protected void handleUploadConflict(OsmApiException e) {
390 String pattern = "Version mismatch: Provided (\\d+), server had: (\\d+) of (\\S+) (\\d+)";
391 Pattern p = Pattern.compile(pattern);
392 Matcher m = p.matcher(e.getErrorHeader());
393 if (m.matches()) {
394 handleUploadConflictForKnownConflict(OsmPrimitiveType.from(m.group(3)), Long.parseLong(m.group(4)), m.group(2),m.group(1));
395 return;
396 }
397 pattern ="The changeset (\\d+) was closed at (.*)";
398 p = Pattern.compile(pattern);
399 m = p.matcher(e.getErrorHeader());
400 if (m.matches()) {
401 handleUploadConflictForClosedChangeset(Long.parseLong(m.group(1)), DateUtils.fromString(m.group(2)));
402 return;
403 }
404 pattern = "Node (\\d+) is still used by way (\\d+).";
405 p = Pattern.compile(pattern);
406 m = p.matcher(e.getErrorHeader());
407 if (m.matches()) {
408 handleUploadConflictForNodeStillInUse(Long.parseLong(m.group(1)), Long.parseLong(m.group(2)));
409 return;
410 }
411 logger.warning(tr("Warning: error header \"{0}\" did not match with an expected pattern", e.getErrorHeader()));
412 handleUploadConflictForUnknownConflict();
413 }
414
415 /**
416 * handles an precondition failed conflict, i.e. an error indicated by a HTTP return code 412.
417 *
418 * @param e the exception
419 */
420 protected void handlePreconditionFailed(OsmApiException e) {
421 String pattern = "Precondition failed: Node (\\d+) is still used by way (\\d+).";
422 Pattern p = Pattern.compile(pattern);
423 Matcher m = p.matcher(e.getErrorHeader());
424 if (m.matches()) {
425 handleUploadConflictForNodeStillInUse(Long.parseLong(m.group(1)), Long.parseLong(m.group(2)));
426 return;
427 }
428 logger.warning(tr("Warning: error header \"{0}\" did not match with an expected pattern", e.getErrorHeader()));
429 ExceptionDialogUtil.explainPreconditionFailed(e);
430 }
431
432 /**
433 * Handles an error due to a delete request on an already deleted
434 * {@see OsmPrimitive}, i.e. a HTTP response code 410, where we know what
435 * {@see OsmPrimitive} is responsible for the error.
436 *
437 * Reuses functionality of the {@see UpdateSelectionAction} to resolve
438 * conflicts due to mismatches in the deleted state.
439 *
440 * @param primitiveType the type of the primitive
441 * @param id the id of the primitive
442 *
443 * @see UpdateSelectionAction#handlePrimitiveGoneException(long)
444 */
445 protected void handleGoneForKnownPrimitive(OsmPrimitiveType primitiveType, long id) {
446 UpdateSelectionAction act = new UpdateSelectionAction();
447 act.handlePrimitiveGoneException(id,primitiveType);
448 }
449
450 /**
451 * Handles an error which is caused by a delete request for an already deleted
452 * {@see OsmPrimitive} on the server, i.e. a HTTP response code of 410.
453 * Note that an <strong>update</strong> on an already deleted object results
454 * in a 409, not a 410.
455 *
456 * @param e the exception
457 */
458 protected void handleGone(OsmApiPrimitiveGoneException e) {
459 if (e.isKnownPrimitive()) {
460 handleGoneForKnownPrimitive(e.getPrimitiveType(), e.getPrimitiveId());
461 } else {
462 ExceptionDialogUtil.explainGoneForUnknownPrimitive(e);
463 }
464 }
465
466 /**
467 * error handler for any exception thrown during upload
468 *
469 * @param e the exception
470 */
471 protected void handleFailedUpload(Exception e) {
472 // API initialization failed. Notify the user and return.
473 //
474 if (e instanceof OsmApiInitializationException) {
475 ExceptionDialogUtil.explainOsmApiInitializationException((OsmApiInitializationException)e);
476 return;
477 }
478
479 if (e instanceof OsmApiPrimitiveGoneException) {
480 handleGone((OsmApiPrimitiveGoneException)e);
481 return;
482 }
483 if (e instanceof OsmApiException) {
484 OsmApiException ex = (OsmApiException)e;
485 // There was an upload conflict. Let the user decide whether
486 // and how to resolve it
487 //
488 if(ex.getResponseCode() == HttpURLConnection.HTTP_CONFLICT) {
489 handleUploadConflict(ex);
490 return;
491 }
492 // There was a precondition failed. Notify the user.
493 //
494 else if (ex.getResponseCode() == HttpURLConnection.HTTP_PRECON_FAILED) {
495 handlePreconditionFailed(ex);
496 return;
497 }
498 // Tried to update or delete a primitive which never existed on
499 // the server?
500 //
501 else if (ex.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
502 ExceptionDialogUtil.explainNotFound(ex);
503 return;
504 }
505 }
506
507 ExceptionDialogUtil.explainException(e);
508 }
509
510 /**
511 * The asynchronous task to update a specific id
512 *
513 */
514 class UpdatePrimitiveTask extends PleaseWaitRunnable {
515
516 private boolean uploadCancelled = false;
517 private boolean uploadFailed = false;
518 private Exception lastException = null;
519 private long id;
520 private OsmPrimitiveType type;
521
522 public UpdatePrimitiveTask(OsmPrimitiveType type, long id) {
523 super(tr("Updating primitive"),false /* don't ignore exceptions */);
524 this.id = id;
525 this.type = type;
526 }
527
528 @Override protected void realRun() throws SAXException, IOException {
529 try {
530 UpdateSelectionAction act = new UpdateSelectionAction();
531 act.updatePrimitive(type, id);
532 } catch (Exception sxe) {
533 if (uploadCancelled) {
534 System.out.println("Ignoring exception caught because upload is canceled. Exception is: " + sxe.toString());
535 return;
536 }
537 uploadFailed = true;
538 lastException = sxe;
539 }
540 }
541
542 @Override protected void finish() {
543 if (uploadFailed) {
544 handleFailedUpload(lastException);
545 }
546 }
547
548 @Override protected void cancel() {
549 OsmApi.getOsmApi().cancel();
550 uploadCancelled = true;
551 }
552 }
553
554 public UploadPrimitivesTask createUploadTask(OsmDataLayer layer, Collection<OsmPrimitive> toUpload, Changeset changeset, boolean closeChangesetAfterUpload) {
555 return new UploadPrimitivesTask(layer, toUpload, changeset, closeChangesetAfterUpload);
556 }
557
558 /**
559 * The task for uploading a collection of primitives
560 *
561 */
562 public class UploadPrimitivesTask extends PleaseWaitRunnable {
563 private boolean uploadCancelled = false;
564 private Exception lastException = null;
565 private Collection <OsmPrimitive> toUpload;
566 private OsmServerWriter writer;
567 private OsmDataLayer layer;
568 private Changeset changeset;
569 private boolean closeChangesetAfterUpload;
570 private HashSet<OsmPrimitive> processedPrimitives;
571
572 /**
573 *
574 * @param layer the OSM data layer for which data is uploaded
575 * @param toUpload the collection of primitives to upload
576 * @param changeset the changeset to use for uploading
577 * @param closeChangesetAfterUpload true, if the changeset is to be closed after uploading
578 */
579 private UploadPrimitivesTask(OsmDataLayer layer, Collection <OsmPrimitive> toUpload, Changeset changeset, boolean closeChangesetAfterUpload) {
580 super(tr("Uploading data for layer ''{0}''", layer.getName()),false /* don't ignore exceptions */);
581 this.toUpload = toUpload;
582 this.layer = layer;
583 this.changeset = changeset;
584 this.closeChangesetAfterUpload = closeChangesetAfterUpload;
585 this.processedPrimitives = new HashSet<OsmPrimitive>();
586 }
587
588 protected OsmPrimitive getPrimitive(OsmPrimitiveType type, long id) {
589 for (OsmPrimitive p: toUpload) {
590 if (OsmPrimitiveType.from(p).equals(type) && p.getId() == id)
591 return p;
592 }
593 return null;
594 }
595
596 /**
597 * Retries to recover the upload operation from an exception which was thrown because
598 * an uploaded primitive was already deleted on the server.
599 *
600 * @param e the exception throw by the API
601 * @param monitor a progress monitor
602 * @throws OsmTransferException thrown if we can't recover from the exception
603 */
604 protected void recoverFromGoneOnServer(OsmApiPrimitiveGoneException e, ProgressMonitor monitor) throws OsmTransferException{
605 if (!e.isKnownPrimitive()) throw e;
606 OsmPrimitive p = getPrimitive(e.getPrimitiveType(), e.getPrimitiveId());
607 if (p == null) throw e;
608 if (p.isDeleted()) {
609 // we tried to delete an already deleted primitive.
610 //
611 System.out.println(tr("Warning: object ''{0}'' is already deleted on the server. Skipping this object and retrying to upload.", p.getDisplayName(DefaultNameFormatter.getInstance())));
612 monitor.appendLogMessage(tr("Object ''{0}'' is already deleted. Skipping object in upload.",p.getDisplayName(DefaultNameFormatter.getInstance())));
613 processedPrimitives.addAll(writer.getProcessedPrimitives());
614 processedPrimitives.add(p);
615 toUpload.removeAll(processedPrimitives);
616 return;
617 }
618 // exception was thrown because we tried to *update* an already deleted
619 // primitive. We can't resolve this automatically. Re-throw exception,
620 // a conflict is going to be created later.
621 throw e;
622 }
623
624 @Override protected void realRun() throws SAXException, IOException {
625 writer = new OsmServerWriter();
626 try {
627 while(true) {
628 try {
629 getProgressMonitor().subTask(tr("Uploading {0} objects ...", toUpload.size()));
630 writer.uploadOsm(layer.data.getVersion(), toUpload, changeset, getProgressMonitor().createSubTaskMonitor(1, false));
631 processedPrimitives.addAll(writer.getProcessedPrimitives());
632 // if we get here we've successfully uploaded the data. Exit the loop.
633 //
634 break;
635 } catch(OsmApiPrimitiveGoneException e) {
636 // try to recover from the 410 Gone
637 recoverFromGoneOnServer(e, getProgressMonitor());
638 }
639 }
640 // if required close the changeset
641 //
642 if (closeChangesetAfterUpload) {
643 if (changeset != null && changeset.getId() > 0) {
644 OsmApi.getOsmApi().closeChangeset(changeset, progressMonitor.createSubTaskMonitor(0,false));
645 }
646 }
647 } catch (Exception e) {
648 if (uploadCancelled) {
649 System.out.println(tr("Ignoring caught exception because upload is canceled. Exception is: {0}", e.toString()));
650 return;
651 }
652 lastException = e;
653 }
654 }
655
656 @Override protected void finish() {
657 if (uploadCancelled)
658 return;
659
660 // we always clean up the data, even in case of errors. It's possible the data was
661 // partially uploaded
662 //
663 layer.cleanupAfterUpload(processedPrimitives);
664 layer.fireDataChange();
665 if (lastException != null) {
666 handleFailedUpload(lastException);
667 }
668 layer.onPostUploadToServer();
669 if (lastException != null && lastException instanceof ChangesetClosedException) {
670 UploadDialog.getUploadDialog().removeChangeset(changeset);
671 } else {
672 UploadDialog.getUploadDialog().setOrUpdateChangeset(changeset);
673 }
674 }
675
676 @Override protected void cancel() {
677 uploadCancelled = true;
678 if (writer != null) {
679 writer.cancel();
680 }
681 }
682 }
683}
Note: See TracBrowser for help on using the repository browser.