From faadcb49231b0a639a0e1e47783423381b8c9022 Mon Sep 17 00:00:00 2001
From: Michael Zangl <michael.zangl@student.kit.edu>
Date: Thu, 6 Aug 2015 14:02:04 +0200
Subject: [PATCH 1/3] Revert "Temporary fix lockups on data layer removal when
Validation layer is present"
This reverts commit f3f0ab13d3c24ceb75494616fb4fbb187dc1eac0.
---
src/org/openstreetmap/josm/gui/MapView.java | 220 +++++++++++++++++++---------
1 file changed, 154 insertions(+), 66 deletions(-)
diff --git a/src/org/openstreetmap/josm/gui/MapView.java b/src/org/openstreetmap/josm/gui/MapView.java
index bbe824a..ef6d0e8 100644
a
|
b
|
import java.util.List;
|
31 | 31 | import java.util.ListIterator; |
32 | 32 | import java.util.Set; |
33 | 33 | import java.util.concurrent.CopyOnWriteArrayList; |
| 34 | import java.util.concurrent.locks.ReentrantReadWriteLock; |
34 | 35 | |
35 | 36 | import javax.swing.AbstractButton; |
36 | 37 | import javax.swing.ActionMap; |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
200 | 201 | * @param newLayer The new active layer. |
201 | 202 | */ |
202 | 203 | protected void fireActiveLayerChanged(Layer oldLayer, Layer newLayer) { |
| 204 | checkLayerLockNotHeld(); |
203 | 205 | for (LayerChangeListener l : layerChangeListeners) { |
204 | 206 | l.activeLayerChange(oldLayer, newLayer); |
205 | 207 | } |
206 | 208 | } |
207 | 209 | |
208 | 210 | protected void fireLayerAdded(Layer newLayer) { |
| 211 | checkLayerLockNotHeld(); |
209 | 212 | for (MapView.LayerChangeListener l : MapView.layerChangeListeners) { |
210 | 213 | l.layerAdded(newLayer); |
211 | 214 | } |
212 | 215 | } |
213 | 216 | |
214 | 217 | protected void fireLayerRemoved(Layer layer) { |
| 218 | checkLayerLockNotHeld(); |
215 | 219 | for (MapView.LayerChangeListener l : MapView.layerChangeListeners) { |
216 | 220 | l.layerRemoved(layer); |
217 | 221 | } |
218 | 222 | } |
219 | 223 | |
220 | 224 | protected void fireEditLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) { |
| 225 | checkLayerLockNotHeld(); |
221 | 226 | for (EditLayerChangeListener l : editLayerChangeListeners) { |
222 | 227 | l.editLayerChanged(oldLayer, newLayer); |
223 | 228 | } |
224 | 229 | } |
225 | 230 | |
226 | 231 | /** |
| 232 | * This is a simple invariant check that tests if the {@link #layerLock} is not write locked. |
| 233 | * This should be the case whenever a layer listener is invoked. |
| 234 | */ |
| 235 | private void checkLayerLockNotHeld() { |
| 236 | if (layerLock.isWriteLockedByCurrentThread()) { |
| 237 | Main.warn("layerLock is write-held while a listener was called."); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | /** |
227 | 242 | * A list of all layers currently loaded. Locked by {@link #layerLock}. |
228 | 243 | */ |
229 | 244 | private final transient List<Layer> layers = new ArrayList<>(); |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
234 | 249 | * <p> |
235 | 250 | * The read lock is always held while those fields are read or while layer change listeners are fired. |
236 | 251 | */ |
237 | | //private final ReentrantReadWriteLock layerLock = new ReentrantReadWriteLock(); |
| 252 | private final ReentrantReadWriteLock layerLock = new ReentrantReadWriteLock(); |
238 | 253 | |
239 | 254 | /** |
240 | 255 | * The play head marker: there is only one of these so it isn't in any specific layer |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
360 | 375 | * @param layer the GPX layer |
361 | 376 | */ |
362 | 377 | protected void addGpxLayer(GpxLayer layer) { |
363 | | synchronized (layers) { |
| 378 | layerLock.writeLock().lock(); |
| 379 | try { |
364 | 380 | if (layers.isEmpty()) { |
365 | 381 | layers.add(layer); |
366 | 382 | return; |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
376 | 392 | } |
377 | 393 | } |
378 | 394 | layers.add(0, layer); |
| 395 | } finally { |
| 396 | layerLock.writeLock().unlock(); |
379 | 397 | } |
380 | 398 | } |
381 | 399 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
390 | 408 | Layer oldActiveLayer = activeLayer; |
391 | 409 | OsmDataLayer oldEditLayer = editLayer; |
392 | 410 | |
393 | | synchronized (layers) { |
394 | | if (layer instanceof MarkerLayer && playHeadMarker == null) { |
395 | | playHeadMarker = PlayHeadMarker.create(); |
396 | | } |
| 411 | layerLock.writeLock().lock(); |
| 412 | layerLock.readLock().lock(); |
| 413 | try { |
| 414 | try { |
| 415 | if (layer instanceof MarkerLayer && playHeadMarker == null) { |
| 416 | playHeadMarker = PlayHeadMarker.create(); |
| 417 | } |
397 | 418 | |
398 | | if (layer instanceof GpxLayer) { |
399 | | addGpxLayer((GpxLayer) layer); |
400 | | } else if (layers.isEmpty()) { |
401 | | layers.add(layer); |
402 | | } else if (layer.isBackgroundLayer()) { |
403 | | int i = 0; |
404 | | for (; i < layers.size(); i++) { |
405 | | if (layers.get(i).isBackgroundLayer()) { |
406 | | break; |
| 419 | if (layer instanceof GpxLayer) { |
| 420 | addGpxLayer((GpxLayer) layer); |
| 421 | } else if (layers.isEmpty()) { |
| 422 | layers.add(layer); |
| 423 | } else if (layer.isBackgroundLayer()) { |
| 424 | int i = 0; |
| 425 | for (; i < layers.size(); i++) { |
| 426 | if (layers.get(i).isBackgroundLayer()) { |
| 427 | break; |
| 428 | } |
407 | 429 | } |
| 430 | layers.add(i, layer); |
| 431 | } else { |
| 432 | layers.add(0, layer); |
408 | 433 | } |
409 | | layers.add(i, layer); |
410 | | } else { |
411 | | layers.add(0, layer); |
412 | | } |
413 | 434 | |
414 | | if (isOsmDataLayer || oldActiveLayer == null) { |
415 | | // autoselect the new layer |
416 | | listenersToFire.addAll(setActiveLayer(layer, true)); |
| 435 | if (isOsmDataLayer || oldActiveLayer == null) { |
| 436 | // autoselect the new layer |
| 437 | listenersToFire.addAll(setActiveLayer(layer, true)); |
| 438 | } |
| 439 | } finally { |
| 440 | layerLock.writeLock().unlock(); |
417 | 441 | } |
418 | 442 | |
419 | 443 | fireLayerAdded(layer); |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
424 | 448 | layer.addPropertyChangeListener(this); |
425 | 449 | Main.addProjectionChangeListener(layer); |
426 | 450 | AudioPlayer.reset(); |
| 451 | } finally { |
| 452 | layerLock.readLock().unlock(); |
427 | 453 | } |
428 | 454 | if (!listenersToFire.isEmpty()) { |
429 | 455 | repaint(); |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
432 | 458 | |
433 | 459 | @Override |
434 | 460 | protected DataSet getCurrentDataSet() { |
435 | | synchronized (layers) { |
| 461 | layerLock.readLock().lock(); |
| 462 | try { |
436 | 463 | if (editLayer != null) |
437 | 464 | return editLayer.data; |
438 | 465 | else |
439 | 466 | return null; |
| 467 | } finally { |
| 468 | layerLock.readLock().unlock(); |
440 | 469 | } |
441 | 470 | } |
442 | 471 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
446 | 475 | * @return true if the active data layer (edit layer) is drawable, false otherwise |
447 | 476 | */ |
448 | 477 | public boolean isActiveLayerDrawable() { |
449 | | synchronized (layers) { |
| 478 | layerLock.readLock().lock(); |
| 479 | try { |
450 | 480 | return editLayer != null; |
| 481 | } finally { |
| 482 | layerLock.readLock().unlock(); |
451 | 483 | } |
452 | 484 | } |
453 | 485 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
457 | 489 | * @return true if the active data layer (edit layer) is visible, false otherwise |
458 | 490 | */ |
459 | 491 | public boolean isActiveLayerVisible() { |
460 | | synchronized (layers) { |
| 492 | layerLock.readLock().lock(); |
| 493 | try { |
461 | 494 | return isActiveLayerDrawable() && editLayer.isVisible(); |
| 495 | } finally { |
| 496 | layerLock.readLock().unlock(); |
462 | 497 | } |
463 | 498 | } |
464 | 499 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
499 | 534 | Layer oldActiveLayer = activeLayer; |
500 | 535 | OsmDataLayer oldEditLayer = editLayer; |
501 | 536 | |
502 | | synchronized (layers) { |
503 | | List<Layer> layersList = new ArrayList<>(layers); |
| 537 | layerLock.writeLock().lock(); |
| 538 | layerLock.readLock().lock(); |
| 539 | try { |
| 540 | try { |
| 541 | List<Layer> layersList = new ArrayList<>(layers); |
504 | 542 | |
505 | | if (!layersList.remove(layer)) |
506 | | return; |
| 543 | if (!layersList.remove(layer)) |
| 544 | return; |
507 | 545 | |
508 | | listenersToFire = setEditLayer(layersList); |
| 546 | listenersToFire = setEditLayer(layersList); |
509 | 547 | |
510 | | if (layer == activeLayer) { |
511 | | listenersToFire.addAll(setActiveLayer(determineNextActiveLayer(layersList), false)); |
512 | | } |
| 548 | if (layer == activeLayer) { |
| 549 | listenersToFire.addAll(setActiveLayer(determineNextActiveLayer(layersList), false)); |
| 550 | } |
513 | 551 | |
514 | | if (layer instanceof OsmDataLayer) { |
515 | | ((OsmDataLayer) layer).removeLayerPropertyChangeListener(this); |
516 | | } |
| 552 | if (layer instanceof OsmDataLayer) { |
| 553 | ((OsmDataLayer) layer).removeLayerPropertyChangeListener(this); |
| 554 | } |
517 | 555 | |
518 | | layers.remove(layer); |
519 | | Main.removeProjectionChangeListener(layer); |
| 556 | layers.remove(layer); |
| 557 | Main.removeProjectionChangeListener(layer); |
520 | 558 | |
| 559 | } finally { |
| 560 | layerLock.writeLock().unlock(); |
| 561 | } |
521 | 562 | onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire); |
522 | 563 | fireLayerRemoved(layer); |
523 | 564 | layer.removePropertyChangeListener(this); |
524 | 565 | layer.destroy(); |
525 | 566 | AudioPlayer.reset(); |
| 567 | } finally { |
| 568 | layerLock.readLock().unlock(); |
526 | 569 | } |
527 | 570 | repaint(); |
528 | 571 | } |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
562 | 605 | Layer oldActiveLayer = activeLayer; |
563 | 606 | OsmDataLayer oldEditLayer = editLayer; |
564 | 607 | |
565 | | synchronized (layers) { |
566 | | int curLayerPos = layers.indexOf(layer); |
567 | | if (curLayerPos == -1) |
568 | | throw new IllegalArgumentException(tr("Layer not in list.")); |
569 | | if (pos == curLayerPos) |
570 | | return; // already in place. |
571 | | layers.remove(curLayerPos); |
572 | | if (pos >= layers.size()) { |
573 | | layers.add(layer); |
574 | | } else { |
575 | | layers.add(pos, layer); |
| 608 | layerLock.writeLock().lock(); |
| 609 | layerLock.readLock().lock(); |
| 610 | try { |
| 611 | try { |
| 612 | int curLayerPos = layers.indexOf(layer); |
| 613 | if (curLayerPos == -1) |
| 614 | throw new IllegalArgumentException(tr("Layer not in list.")); |
| 615 | if (pos == curLayerPos) |
| 616 | return; // already in place. |
| 617 | layers.remove(curLayerPos); |
| 618 | if (pos >= layers.size()) { |
| 619 | layers.add(layer); |
| 620 | } else { |
| 621 | layers.add(pos, layer); |
| 622 | } |
| 623 | listenersToFire = setEditLayer(layers); |
| 624 | } finally { |
| 625 | layerLock.writeLock().unlock(); |
576 | 626 | } |
577 | | listenersToFire = setEditLayer(layers); |
578 | 627 | onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire); |
579 | 628 | AudioPlayer.reset(); |
| 629 | } finally { |
| 630 | layerLock.readLock().unlock(); |
580 | 631 | } |
581 | 632 | repaint(); |
582 | 633 | } |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
589 | 640 | */ |
590 | 641 | public int getLayerPos(Layer layer) { |
591 | 642 | int curLayerPos; |
592 | | synchronized (layers) { |
| 643 | layerLock.readLock().lock(); |
| 644 | try { |
593 | 645 | curLayerPos = layers.indexOf(layer); |
| 646 | } finally { |
| 647 | layerLock.readLock().unlock(); |
594 | 648 | } |
595 | 649 | if (curLayerPos == -1) |
596 | 650 | throw new IllegalArgumentException(tr("Layer not in list.")); |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
607 | 661 | * first, layer with the highest Z-Order last. |
608 | 662 | */ |
609 | 663 | public List<Layer> getVisibleLayersInZOrder() { |
610 | | synchronized (layers) { |
| 664 | layerLock.readLock().lock(); |
| 665 | try { |
611 | 666 | List<Layer> ret = new ArrayList<>(); |
612 | 667 | // This is set while we delay the addition of the active layer. |
613 | 668 | boolean activeLayerDelayed = false; |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
632 | 687 | ret.add(activeLayer); |
633 | 688 | } |
634 | 689 | return ret; |
| 690 | } finally { |
| 691 | layerLock.readLock().unlock(); |
635 | 692 | } |
636 | 693 | } |
637 | 694 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
820 | 877 | * @return An unmodifiable collection of all layers |
821 | 878 | */ |
822 | 879 | public Collection<Layer> getAllLayers() { |
823 | | synchronized (layers) { |
| 880 | layerLock.readLock().lock(); |
| 881 | try { |
824 | 882 | return Collections.unmodifiableCollection(new ArrayList<>(layers)); |
| 883 | } finally { |
| 884 | layerLock.readLock().unlock(); |
825 | 885 | } |
826 | 886 | } |
827 | 887 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
829 | 889 | * @return An unmodifiable ordered list of all layers |
830 | 890 | */ |
831 | 891 | public List<Layer> getAllLayersAsList() { |
832 | | synchronized (layers) { |
| 892 | layerLock.readLock().lock(); |
| 893 | try { |
833 | 894 | return Collections.unmodifiableList(new ArrayList<>(layers)); |
| 895 | } finally { |
| 896 | layerLock.readLock().unlock(); |
834 | 897 | } |
835 | 898 | } |
836 | 899 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
855 | 918 | * @return the number of layers managed by this map view |
856 | 919 | */ |
857 | 920 | public int getNumLayers() { |
858 | | synchronized (layers) { |
| 921 | layerLock.readLock().lock(); |
| 922 | try { |
859 | 923 | return layers.size(); |
| 924 | } finally { |
| 925 | layerLock.readLock().unlock(); |
860 | 926 | } |
861 | 927 | } |
862 | 928 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
920 | 986 | * @throws IllegalArgumentException if layer is not in the lis of layers |
921 | 987 | */ |
922 | 988 | public void setActiveLayer(Layer layer) { |
| 989 | layerLock.writeLock().lock(); |
| 990 | layerLock.readLock().lock(); |
923 | 991 | EnumSet<LayerListenerType> listenersToFire; |
924 | | |
925 | | synchronized (layers) { |
926 | | Layer oldActiveLayer = activeLayer; |
927 | | OsmDataLayer oldEditLayer = editLayer; |
928 | | listenersToFire = setActiveLayer(layer, true); |
| 992 | Layer oldActiveLayer = activeLayer; |
| 993 | OsmDataLayer oldEditLayer = editLayer; |
| 994 | try { |
| 995 | try { |
| 996 | listenersToFire = setActiveLayer(layer, true); |
| 997 | } finally { |
| 998 | layerLock.writeLock().unlock(); |
| 999 | } |
929 | 1000 | onActiveEditLayerChanged(oldActiveLayer, oldEditLayer, listenersToFire); |
| 1001 | } finally { |
| 1002 | layerLock.readLock().unlock(); |
930 | 1003 | } |
931 | 1004 | repaint(); |
932 | 1005 | } |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
959 | 1032 | * @return the currently active layer (may be null) |
960 | 1033 | */ |
961 | 1034 | public Layer getActiveLayer() { |
962 | | synchronized (layers) { |
| 1035 | layerLock.readLock().lock(); |
| 1036 | try { |
963 | 1037 | return activeLayer; |
| 1038 | } finally { |
| 1039 | layerLock.readLock().unlock(); |
964 | 1040 | } |
965 | 1041 | } |
966 | 1042 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
1015 | 1091 | * @return the current edit layer. May be null. |
1016 | 1092 | */ |
1017 | 1093 | public OsmDataLayer getEditLayer() { |
1018 | | synchronized (layers) { |
| 1094 | layerLock.readLock().lock(); |
| 1095 | try { |
1019 | 1096 | return editLayer; |
| 1097 | } finally { |
| 1098 | layerLock.readLock().unlock(); |
1020 | 1099 | } |
1021 | 1100 | } |
1022 | 1101 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
1027 | 1106 | * @return true if the list of layers managed by this map view contain layer |
1028 | 1107 | */ |
1029 | 1108 | public boolean hasLayer(Layer layer) { |
1030 | | synchronized (layers) { |
| 1109 | layerLock.readLock().lock(); |
| 1110 | try { |
1031 | 1111 | return layers.contains(layer); |
| 1112 | } finally { |
| 1113 | layerLock.readLock().unlock(); |
1032 | 1114 | } |
1033 | 1115 | } |
1034 | 1116 | |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
1093 | 1175 | */ |
1094 | 1176 | protected void refreshTitle() { |
1095 | 1177 | if (Main.parent != null) { |
1096 | | synchronized (layers) { |
| 1178 | layerLock.readLock().lock(); |
| 1179 | try { |
1097 | 1180 | boolean dirty = editLayer != null && |
1098 | 1181 | (editLayer.requiresSaveToFile() || (editLayer.requiresUploadToServer() && !editLayer.isUploadDiscouraged())); |
1099 | 1182 | ((JFrame) Main.parent).setTitle((dirty ? "* " : "") + tr("Java OpenStreetMap Editor")); |
1100 | 1183 | ((JFrame) Main.parent).getRootPane().putClientProperty("Window.documentModified", dirty); |
| 1184 | } finally { |
| 1185 | layerLock.readLock().unlock(); |
1101 | 1186 | } |
1102 | 1187 | } |
1103 | 1188 | } |
… |
… |
implements PropertyChangeListener, PreferenceChangedListener, OsmDataLayer.Layer
|
1123 | 1208 | if (mapMover != null) { |
1124 | 1209 | mapMover.destroy(); |
1125 | 1210 | } |
1126 | | synchronized (layers) { |
| 1211 | layerLock.writeLock().lock(); |
| 1212 | try { |
1127 | 1213 | activeLayer = null; |
1128 | 1214 | changedLayer = null; |
1129 | 1215 | editLayer = null; |
1130 | 1216 | layers.clear(); |
1131 | | nonChangedLayers.clear(); |
| 1217 | } finally { |
| 1218 | layerLock.writeLock().unlock(); |
1132 | 1219 | } |
| 1220 | nonChangedLayers.clear(); |
1133 | 1221 | synchronized (temporaryLayers) { |
1134 | 1222 | temporaryLayers.clear(); |
1135 | 1223 | } |