Changeset 3348 in josm
- Timestamp:
- 2010-06-27T17:07:49+02:00 (14 years ago)
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
r3316 r3348 15 15 import java.util.List; 16 16 import java.util.Map; 17 import java.util.concurrent.locks.Lock; 18 import java.util.concurrent.locks.ReadWriteLock; 19 import java.util.concurrent.locks.ReentrantReadWriteLock; 17 20 18 21 import org.openstreetmap.josm.data.SelectionChangedListener; … … 42 45 public class DataSet implements Cloneable { 43 46 47 /** 48 * Maximum number of events that can be fired between beginUpdate/endUpdate to be send as single events (ie without DatasetChangedEvent) 49 */ 50 private static final int MAX_SINGLE_EVENTS = 30; 51 52 /** 53 * Maximum number of events to kept between beginUpdate/endUpdate. When more events are created, that simple DatasetChangedEvent is sent) 54 */ 55 private static final int MAX_EVENTS = 1000; 56 44 57 private static class IdHash implements Hash<PrimitiveId,OsmPrimitive> { 45 58 … … 57 70 private Map<PrimitiveId, OsmPrimitive> primitivesMap = allPrimitives.foreignKey(new IdHash()); 58 71 private List<DataSetListener> listeners = new ArrayList<DataSetListener>(); 72 59 73 // Number of open calls to beginUpdate 60 74 private int updateCount; 75 // Events that occurred while dataset was locked but should be fired after write lock is released 76 private final List<AbstractDatasetChangedEvent> cachedEvents = new ArrayList<AbstractDatasetChangedEvent>(); 61 77 62 78 private int highlightUpdateCount; 79 80 private final ReadWriteLock lock = new ReentrantReadWriteLock(); 81 82 public Lock getReadLock() { 83 return lock.readLock(); 84 } 63 85 64 86 /** … … 212 234 */ 213 235 public void addPrimitive(OsmPrimitive primitive) { 214 if (getPrimitiveById(primitive) != null) 215 throw new DataIntegrityProblemException( 216 tr("Unable to add primitive {0} to the dataset because it is already included", primitive.toString())); 217 218 primitive.updatePosition(); // Set cached bbox for way and relation (required for reindexWay and reinexRelation to work properly) 219 if (primitive instanceof Node) { 220 nodes.add((Node) primitive); 221 } else if (primitive instanceof Way) { 222 ways.add((Way) primitive); 223 } else if (primitive instanceof Relation) { 224 relations.add((Relation) primitive); 225 } 226 allPrimitives.add(primitive); 227 primitive.setDataset(this); 228 firePrimitivesAdded(Collections.singletonList(primitive), false); 236 beginUpdate(); 237 try { 238 if (getPrimitiveById(primitive) != null) 239 throw new DataIntegrityProblemException( 240 tr("Unable to add primitive {0} to the dataset because it is already included", primitive.toString())); 241 242 primitive.updatePosition(); // Set cached bbox for way and relation (required for reindexWay and reinexRelation to work properly) 243 if (primitive instanceof Node) { 244 nodes.add((Node) primitive); 245 } else if (primitive instanceof Way) { 246 ways.add((Way) primitive); 247 } else if (primitive instanceof Relation) { 248 relations.add((Relation) primitive); 249 } 250 allPrimitives.add(primitive); 251 primitive.setDataset(this); 252 firePrimitivesAdded(Collections.singletonList(primitive), false); 253 } finally { 254 endUpdate(); 255 } 229 256 } 230 257 231 258 public OsmPrimitive addPrimitive(PrimitiveData data) { 232 OsmPrimitive result; 233 if (data instanceof NodeData) { 234 result = new Node(); 235 } else if (data instanceof WayData) { 236 result = new Way(); 237 } else if (data instanceof RelationData) { 238 result = new Relation(); 239 } else 240 throw new AssertionError(); 241 result.setDataset(this); 242 result.load(data); 243 addPrimitive(result); 244 return result; 259 beginUpdate(); 260 try { 261 OsmPrimitive result; 262 if (data instanceof NodeData) { 263 result = new Node(); 264 } else if (data instanceof WayData) { 265 result = new Way(); 266 } else if (data instanceof RelationData) { 267 result = new Relation(); 268 } else 269 throw new AssertionError(); 270 result.setDataset(this); 271 result.load(data); 272 addPrimitive(result); 273 return result; 274 } finally { 275 endUpdate(); 276 } 245 277 } 246 278 … … 255 287 */ 256 288 public void removePrimitive(PrimitiveId primitiveId) { 257 OsmPrimitive primitive = getPrimitiveByIdChecked(primitiveId); 258 if (primitive == null) 259 return; 260 if (primitive instanceof Node) { 261 nodes.remove(primitive); 262 } else if (primitive instanceof Way) { 263 ways.remove(primitive); 264 } else if (primitive instanceof Relation) { 265 relations.remove(primitive); 266 } 267 selectedPrimitives.remove(primitive); 268 allPrimitives.remove(primitive); 269 primitive.setDataset(null); 270 firePrimitivesRemoved(Collections.singletonList(primitive), false); 289 beginUpdate(); 290 try { 291 OsmPrimitive primitive = getPrimitiveByIdChecked(primitiveId); 292 if (primitive == null) 293 return; 294 if (primitive instanceof Node) { 295 nodes.remove(primitive); 296 } else if (primitive instanceof Way) { 297 ways.remove(primitive); 298 } else if (primitive instanceof Relation) { 299 relations.remove(primitive); 300 } 301 selectedPrimitives.remove(primitive); 302 allPrimitives.remove(primitive); 303 primitive.setDataset(null); 304 firePrimitivesRemoved(Collections.singletonList(primitive), false); 305 } finally { 306 endUpdate(); 307 } 271 308 } 272 309 … … 492 529 */ 493 530 494 // public void setDisabled(OsmPrimitive... osm) {495 // if (osm.length == 1 && osm[0] == null) {496 // setDisabled();497 // return;498 // }499 // clearDisabled(allPrimitives());500 // for (OsmPrimitive o : osm)501 // if (o != null) {502 // o.setDisabled(true);503 // }504 // }505 //506 // public void setDisabled(Collection<? extends OsmPrimitive> selection) {507 // clearDisabled(nodes);508 // clearDisabled(ways);509 // clearDisabled(relations);510 // for (OsmPrimitive osm : selection) {511 // osm.setDisabled(true);512 // }513 // }514 //515 // /**516 // * Remove the disabled parameter from every value in the collection.517 // * @param list The collection to remove the disabled parameter from.518 // */519 // private void clearDisabled(Collection<? extends OsmPrimitive> list) {520 // for (OsmPrimitive osm : list) {521 // osm.setDisabled(false);522 // }523 // }524 //525 //526 // public void setFiltered(Collection<? extends OsmPrimitive> selection) {527 // clearFiltered(nodes);528 // clearFiltered(ways);529 // clearFiltered(relations);530 // for (OsmPrimitive osm : selection) {531 // osm.setFiltered(true);532 // }533 // }534 //535 // public void setFiltered(OsmPrimitive... osm) {536 // if (osm.length == 1 && osm[0] == null) {537 // setFiltered();538 // return;539 // }540 // clearFiltered(nodes);541 // clearFiltered(ways);542 // clearFiltered(relations);543 // for (OsmPrimitive o : osm)544 // if (o != null) {545 // o.setFiltered(true);546 // }547 // }548 //549 // /**550 // * Remove the filtered parameter from every value in the collection.551 // * @param list The collection to remove the filtered parameter from.552 // */553 // private void clearFiltered(Collection<? extends OsmPrimitive> list) {554 // if (list == null)555 // return;556 // for (OsmPrimitive osm : list) {557 // osm.setFiltered(false);558 // }559 // }531 // public void setDisabled(OsmPrimitive... osm) { 532 // if (osm.length == 1 && osm[0] == null) { 533 // setDisabled(); 534 // return; 535 // } 536 // clearDisabled(allPrimitives()); 537 // for (OsmPrimitive o : osm) 538 // if (o != null) { 539 // o.setDisabled(true); 540 // } 541 // } 542 // 543 // public void setDisabled(Collection<? extends OsmPrimitive> selection) { 544 // clearDisabled(nodes); 545 // clearDisabled(ways); 546 // clearDisabled(relations); 547 // for (OsmPrimitive osm : selection) { 548 // osm.setDisabled(true); 549 // } 550 // } 551 // 552 // /** 553 // * Remove the disabled parameter from every value in the collection. 554 // * @param list The collection to remove the disabled parameter from. 555 // */ 556 // private void clearDisabled(Collection<? extends OsmPrimitive> list) { 557 // for (OsmPrimitive osm : list) { 558 // osm.setDisabled(false); 559 // } 560 // } 561 // 562 // 563 // public void setFiltered(Collection<? extends OsmPrimitive> selection) { 564 // clearFiltered(nodes); 565 // clearFiltered(ways); 566 // clearFiltered(relations); 567 // for (OsmPrimitive osm : selection) { 568 // osm.setFiltered(true); 569 // } 570 // } 571 // 572 // public void setFiltered(OsmPrimitive... osm) { 573 // if (osm.length == 1 && osm[0] == null) { 574 // setFiltered(); 575 // return; 576 // } 577 // clearFiltered(nodes); 578 // clearFiltered(ways); 579 // clearFiltered(relations); 580 // for (OsmPrimitive o : osm) 581 // if (o != null) { 582 // o.setFiltered(true); 583 // } 584 // } 585 // 586 // /** 587 // * Remove the filtered parameter from every value in the collection. 588 // * @param list The collection to remove the filtered parameter from. 589 // */ 590 // private void clearFiltered(Collection<? extends OsmPrimitive> list) { 591 // if (list == null) 592 // return; 593 // for (OsmPrimitive osm : list) { 594 // osm.setFiltered(false); 595 // } 596 // } 560 597 561 598 @Override public DataSet clone() { 562 DataSet ds = new DataSet(); 563 HashMap<OsmPrimitive, OsmPrimitive> primitivesMap = new HashMap<OsmPrimitive, OsmPrimitive>(); 564 for (Node n : nodes) { 565 Node newNode = new Node(n); 566 primitivesMap.put(n, newNode); 567 ds.addPrimitive(newNode); 568 } 569 for (Way w : ways) { 570 Way newWay = new Way(w); 571 primitivesMap.put(w, newWay); 572 List<Node> newNodes = new ArrayList<Node>(); 573 for (Node n: w.getNodes()) { 574 newNodes.add((Node)primitivesMap.get(n)); 575 } 576 newWay.setNodes(newNodes); 577 ds.addPrimitive(newWay); 578 } 579 // Because relations can have other relations as members we first clone all relations 580 // and then get the cloned members 581 for (Relation r : relations) { 582 Relation newRelation = new Relation(r, r.isNew()); 583 newRelation.setMembers(null); 584 primitivesMap.put(r, newRelation); 585 ds.addPrimitive(newRelation); 586 } 587 for (Relation r : relations) { 588 Relation newRelation = (Relation)primitivesMap.get(r); 589 List<RelationMember> newMembers = new ArrayList<RelationMember>(); 590 for (RelationMember rm: r.getMembers()) { 591 newMembers.add(new RelationMember(rm.getRole(), primitivesMap.get(rm.getMember()))); 592 } 593 newRelation.setMembers(newMembers); 594 } 595 for (DataSource source : dataSources) { 596 ds.dataSources.add(new DataSource(source.bounds, source.origin)); 597 } 598 ds.version = version; 599 return ds; 599 getReadLock().lock(); 600 try { 601 DataSet ds = new DataSet(); 602 HashMap<OsmPrimitive, OsmPrimitive> primitivesMap = new HashMap<OsmPrimitive, OsmPrimitive>(); 603 for (Node n : nodes) { 604 Node newNode = new Node(n); 605 primitivesMap.put(n, newNode); 606 ds.addPrimitive(newNode); 607 } 608 for (Way w : ways) { 609 Way newWay = new Way(w); 610 primitivesMap.put(w, newWay); 611 List<Node> newNodes = new ArrayList<Node>(); 612 for (Node n: w.getNodes()) { 613 newNodes.add((Node)primitivesMap.get(n)); 614 } 615 newWay.setNodes(newNodes); 616 ds.addPrimitive(newWay); 617 } 618 // Because relations can have other relations as members we first clone all relations 619 // and then get the cloned members 620 for (Relation r : relations) { 621 Relation newRelation = new Relation(r, r.isNew()); 622 newRelation.setMembers(null); 623 primitivesMap.put(r, newRelation); 624 ds.addPrimitive(newRelation); 625 } 626 for (Relation r : relations) { 627 Relation newRelation = (Relation)primitivesMap.get(r); 628 List<RelationMember> newMembers = new ArrayList<RelationMember>(); 629 for (RelationMember rm: r.getMembers()) { 630 newMembers.add(new RelationMember(rm.getRole(), primitivesMap.get(rm.getMember()))); 631 } 632 newRelation.setMembers(newMembers); 633 } 634 for (DataSource source : dataSources) { 635 ds.dataSources.add(new DataSource(source.bounds, source.origin)); 636 } 637 ds.version = version; 638 return ds; 639 } finally { 640 getReadLock().unlock(); 641 } 600 642 } 601 643 … … 663 705 } 664 706 665 pr otectedvoid deleteWay(Way way) {707 private void deleteWay(Way way) { 666 708 way.setNodes(null); 667 709 way.setDeleted(true); … … 674 716 */ 675 717 public void unlinkNodeFromWays(Node node) { 676 for (Way way: ways) { 677 List<Node> nodes = way.getNodes(); 678 if (nodes.remove(node)) { 679 if (nodes.size() < 2) { 680 deleteWay(way); 681 } else { 682 way.setNodes(nodes); 718 beginUpdate(); 719 try { 720 for (Way way: ways) { 721 List<Node> nodes = way.getNodes(); 722 if (nodes.remove(node)) { 723 if (nodes.size() < 2) { 724 deleteWay(way); 725 } else { 726 way.setNodes(nodes); 727 } 683 728 } 684 729 } 730 } finally { 731 endUpdate(); 685 732 } 686 733 } … … 692 739 */ 693 740 public void unlinkPrimitiveFromRelations(OsmPrimitive primitive) { 694 for (Relation relation : relations) { 695 List<RelationMember> members = relation.getMembers(); 696 697 Iterator<RelationMember> it = members.iterator(); 698 boolean removed = false; 699 while(it.hasNext()) { 700 RelationMember member = it.next(); 701 if (member.getMember().equals(primitive)) { 702 it.remove(); 703 removed = true; 741 beginUpdate(); 742 try { 743 for (Relation relation : relations) { 744 List<RelationMember> members = relation.getMembers(); 745 746 Iterator<RelationMember> it = members.iterator(); 747 boolean removed = false; 748 while(it.hasNext()) { 749 RelationMember member = it.next(); 750 if (member.getMember().equals(primitive)) { 751 it.remove(); 752 removed = true; 753 } 704 754 } 705 } 706 707 if (removed) { 708 relation.setMembers(members); 709 } 755 756 if (removed) { 757 relation.setMembers(members); 758 } 759 } 760 } finally { 761 endUpdate(); 710 762 } 711 763 } … … 718 770 */ 719 771 public void unlinkReferencesToPrimitive(OsmPrimitive referencedPrimitive) { 720 if (referencedPrimitive instanceof Node) { 721 unlinkNodeFromWays((Node)referencedPrimitive); 722 unlinkPrimitiveFromRelations(referencedPrimitive); 723 } else { 724 unlinkPrimitiveFromRelations(referencedPrimitive); 772 beginUpdate(); 773 try { 774 if (referencedPrimitive instanceof Node) { 775 unlinkNodeFromWays((Node)referencedPrimitive); 776 unlinkPrimitiveFromRelations(referencedPrimitive); 777 } else { 778 unlinkPrimitiveFromRelations(referencedPrimitive); 779 } 780 } finally { 781 endUpdate(); 725 782 } 726 783 } … … 804 861 */ 805 862 public void beginUpdate() { 863 lock.writeLock().lock(); 806 864 updateCount++; 807 865 } … … 814 872 updateCount--; 815 873 if (updateCount == 0) { 816 fireDataChanged(); 817 } 874 List<AbstractDatasetChangedEvent> eventsCopy = new ArrayList<AbstractDatasetChangedEvent>(cachedEvents); 875 cachedEvents.clear(); 876 lock.writeLock().unlock(); 877 878 if (!eventsCopy.isEmpty()) { 879 lock.readLock().lock(); 880 try { 881 if (eventsCopy.size() < MAX_SINGLE_EVENTS) { 882 for (AbstractDatasetChangedEvent event: eventsCopy) { 883 fireEventToListeners(event); 884 } 885 } else if (eventsCopy.size() == MAX_EVENTS) { 886 fireEventToListeners(new DataChangedEvent(this)); 887 } else { 888 fireEventToListeners(new DataChangedEvent(this, eventsCopy)); 889 } 890 } finally { 891 lock.readLock().unlock(); 892 } 893 } 894 } else { 895 lock.writeLock().unlock(); 896 } 897 818 898 } else 819 899 throw new AssertionError("endUpdate called without beginUpdate"); 820 900 } 821 901 902 private void fireEventToListeners(AbstractDatasetChangedEvent event) { 903 for (DataSetListener listener: listeners) { 904 event.fire(listener); 905 } 906 } 907 822 908 private void fireEvent(AbstractDatasetChangedEvent event) { 823 if (updateCount == 0) { 824 for (DataSetListener dsl : listeners) { 825 event.fire(dsl); 826 } 827 } 828 } 829 830 private void fireDataChanged() { 831 fireEvent(new DataChangedEvent(this)); 909 if (updateCount == 0) 910 throw new AssertionError("dataset events can be fired only when dataset is locked"); 911 if (cachedEvents.size() < MAX_EVENTS) { 912 cachedEvents.add(event); 913 } 832 914 } 833 915 … … 868 950 869 951 public void clenupDeletedPrimitives() { 870 if (cleanupDeleted(nodes.iterator()) 871 | cleanupDeleted(ways.iterator()) 872 | cleanupDeleted(relations.iterator())) { 873 fireSelectionChanged(); 952 beginUpdate(); 953 try { 954 if (cleanupDeleted(nodes.iterator()) 955 | cleanupDeleted(ways.iterator()) 956 | cleanupDeleted(relations.iterator())) { 957 fireSelectionChanged(); 958 } 959 } finally { 960 endUpdate(); 874 961 } 875 962 } … … 896 983 */ 897 984 public void clear() { 898 clearSelection(); 899 for (OsmPrimitive primitive:allPrimitives) { 900 primitive.setDataset(null); 901 } 902 nodes.clear(); 903 ways.clear(); 904 relations.clear(); 905 allPrimitives.clear(); 985 beginUpdate(); 986 try { 987 clearSelection(); 988 for (OsmPrimitive primitive:allPrimitives) { 989 primitive.setDataset(null); 990 } 991 nodes.clear(); 992 ways.clear(); 993 relations.clear(); 994 allPrimitives.clear(); 995 } finally { 996 endUpdate(); 997 } 906 998 } 907 999 } -
trunk/src/org/openstreetmap/josm/data/osm/Node.java
r3253 r3348 20 20 if(coor != null){ 21 21 if (getDataSet() != null) { 22 getDataSet().fireNodeMoved(this, coor); 22 boolean locked = writeLock(); 23 try { 24 getDataSet().fireNodeMoved(this, coor); 25 } finally { 26 writeUnlock(locked); 27 } 23 28 } else { 24 29 setCoorInternal(coor); … … 115 120 116 121 @Override public void cloneFrom(OsmPrimitive osm) { 117 super.cloneFrom(osm); 118 setCoor(((Node)osm).coor); 122 boolean locked = writeLock(); 123 try { 124 super.cloneFrom(osm); 125 setCoor(((Node)osm).coor); 126 } finally { 127 writeUnlock(locked); 128 } 119 129 } 120 130 … … 132 142 @Override 133 143 public void mergeFrom(OsmPrimitive other) { 134 super.mergeFrom(other); 135 if (!other.isIncomplete()) { 136 setCoor(new LatLon(((Node)other).coor)); 144 boolean locked = writeLock(); 145 try { 146 super.mergeFrom(other); 147 if (!other.isIncomplete()) { 148 setCoor(new LatLon(((Node)other).coor)); 149 } 150 } finally { 151 writeUnlock(locked); 137 152 } 138 153 } 139 154 140 155 @Override public void load(PrimitiveData data) { 141 super.load(data); 142 setCoor(((NodeData)data).getCoor()); 156 boolean locked = writeLock(); 157 try { 158 super.load(data); 159 setCoor(((NodeData)data).getCoor()); 160 } finally { 161 writeUnlock(locked); 162 } 143 163 } 144 164 -
trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
r3342 r3348 345 345 } 346 346 347 protected boolean writeLock() { 348 if (dataSet != null) { 349 dataSet.beginUpdate(); 350 return true; 351 } else 352 return false; 353 } 354 355 protected void writeUnlock(boolean locked) { 356 if (locked) { 357 // It shouldn't be possible for dataset to become null because method calling setDataset would need write lock which is owned by this thread 358 dataSet.endUpdate(); 359 } 360 } 361 362 347 363 /*------------------- 348 364 * OTHER PROPERTIES 349 *------------------- /365 *-------------------*/ 350 366 351 367 /** … … 392 408 */ 393 409 public long getId() { 410 long id = this.id; 394 411 return id >= 0?id:0; 395 412 } … … 434 451 */ 435 452 public void setOsmId(long id, int version) { 436 if (id <= 0) 437 throw new IllegalArgumentException(tr("ID > 0 expected. Got {0}.", id)); 438 if (version <= 0) 439 throw new IllegalArgumentException(tr("Version > 0 expected. Got {0}.", version)); 440 if (dataSet != null && id != this.id) { 441 DataSet datasetCopy = dataSet; 442 // Reindex primitive 443 datasetCopy.removePrimitive(this); 453 boolean locked = writeLock(); 454 try { 455 if (id <= 0) 456 throw new IllegalArgumentException(tr("ID > 0 expected. Got {0}.", id)); 457 if (version <= 0) 458 throw new IllegalArgumentException(tr("Version > 0 expected. Got {0}.", version)); 459 if (dataSet != null && id != this.id) { 460 DataSet datasetCopy = dataSet; 461 // Reindex primitive 462 datasetCopy.removePrimitive(this); 463 this.id = id; 464 datasetCopy.addPrimitive(this); 465 } 444 466 this.id = id; 445 datasetCopy.addPrimitive(this);446 }447 this.id = id;448 this.version = version;449 this.setIncomplete(false);467 this.version = version; 468 this.setIncomplete(false); 469 } finally { 470 writeUnlock(locked); 471 } 450 472 } 451 473 … … 462 484 if (dataSet != null) 463 485 throw new DataIntegrityProblemException("Method cannot be called after primitive was added to the dataset"); 486 487 // Not part of dataset - no lock necessary 464 488 this.id = generateUniqueId(); 465 489 this.version = 0; … … 483 507 */ 484 508 public void setUser(User user) { 485 this.user = user; 509 boolean locked = writeLock(); 510 try { 511 this.user = user; 512 } finally { 513 writeUnlock(locked); 514 } 486 515 } 487 516 … … 506 535 */ 507 536 public void setChangesetId(int changesetId) throws IllegalStateException, IllegalArgumentException { 508 if (this.changesetId == changesetId) 509 return; 510 if (changesetId < 0) 511 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' >= 0 expected, got {1}", "changesetId", changesetId)); 512 if (isNew() && changesetId > 0) 513 throw new IllegalStateException(tr("Cannot assign a changesetId > 0 to a new primitive. Value of changesetId is {0}", changesetId)); 514 int old = this.changesetId; 515 this.changesetId = changesetId; 516 if (dataSet != null) { 517 dataSet.fireChangesetIdChanged(this, old, changesetId); 537 boolean locked = writeLock(); 538 try { 539 if (this.changesetId == changesetId) 540 return; 541 if (changesetId < 0) 542 throw new IllegalArgumentException(MessageFormat.format("Parameter ''{0}'' >= 0 expected, got {1}", "changesetId", changesetId)); 543 if (isNew() && changesetId > 0) 544 throw new IllegalStateException(tr("Cannot assign a changesetId > 0 to a new primitive. Value of changesetId is {0}", changesetId)); 545 546 int old = this.changesetId; 547 this.changesetId = changesetId; 548 if (dataSet != null) { 549 dataSet.fireChangesetIdChanged(this, old, changesetId); 550 } 551 } finally { 552 writeUnlock(locked); 518 553 } 519 554 } … … 529 564 530 565 public void setTimestamp(Date timestamp) { 531 this.timestamp = (int)(timestamp.getTime() / 1000); 566 boolean locked = writeLock(); 567 try { 568 this.timestamp = (int)(timestamp.getTime() / 1000); 569 } finally { 570 writeUnlock(locked); 571 } 532 572 } 533 573 … … 554 594 private volatile short flags = FLAG_VISIBLE; // visible per default 555 595 556 private void updateFlags (int flag, boolean value) {596 private void updateFlagsNoLock(int flag, boolean value) { 557 597 if (value) { 558 598 flags |= flag; … … 562 602 } 563 603 604 private void updateFlags(int flag, boolean value) { 605 boolean locked = writeLock(); 606 try { 607 updateFlagsNoLock(flag, value); 608 } finally { 609 writeUnlock(locked); 610 } 611 } 612 564 613 /** 565 614 * Make the primitive disabled (e.g. if a filter applies). … … 569 618 */ 570 619 public void setDisabledState(boolean hide) { 571 flags |= FLAG_DISABLED; 572 if (hide) { 573 flags |= FLAG_HIDE_IF_DISABLED; 574 } else { 575 flags &= ~FLAG_HIDE_IF_DISABLED; 620 boolean locked = writeLock(); 621 try { 622 updateFlagsNoLock(FLAG_DISABLED, true); 623 updateFlagsNoLock(FLAG_HIDE_IF_DISABLED, hide); 624 } finally { 625 writeUnlock(locked); 576 626 } 577 627 } … … 688 738 */ 689 739 public void setVisible(boolean visible) throws IllegalStateException{ 690 if (isNew() && visible == false) 691 throw new IllegalStateException(tr("A primitive with ID = 0 cannot be invisible.")); 692 updateFlags(FLAG_VISIBLE, visible); 740 boolean locked = writeLock(); 741 try { 742 if (isNew() && visible == false) 743 throw new IllegalStateException(tr("A primitive with ID = 0 cannot be invisible.")); 744 updateFlagsNoLock(FLAG_VISIBLE, visible); 745 } finally { 746 writeUnlock(locked); 747 } 693 748 } 694 749 … … 701 756 */ 702 757 public void setDeleted(boolean deleted) { 703 updateFlags(FLAG_DELETED, deleted); 704 setModified(deleted ^ !isVisible()); 705 if (dataSet != null) { 706 if (deleted) { 707 dataSet.firePrimitivesRemoved(Collections.singleton(this), false); 708 } else { 709 dataSet.firePrimitivesAdded(Collections.singleton(this), false); 710 } 758 boolean locked = writeLock(); 759 try { 760 updateFlagsNoLock(FLAG_DELETED, deleted); 761 setModified(deleted ^ !isVisible()); 762 if (dataSet != null) { 763 if (deleted) { 764 dataSet.firePrimitivesRemoved(Collections.singleton(this), false); 765 } else { 766 dataSet.firePrimitivesAdded(Collections.singleton(this), false); 767 } 768 } 769 } finally { 770 writeUnlock(locked); 711 771 } 712 772 } … … 718 778 */ 719 779 private void setIncomplete(boolean incomplete) { 720 if (dataSet != null && incomplete != this.isIncomplete()) { 721 if (incomplete) { 722 dataSet.firePrimitivesRemoved(Collections.singletonList(this), true); 723 } else { 724 dataSet.firePrimitivesAdded(Collections.singletonList(this), true); 725 } 726 } 727 updateFlags(FLAG_INCOMPLETE, incomplete); 780 boolean locked = writeLock(); 781 try { 782 if (dataSet != null && incomplete != this.isIncomplete()) { 783 if (incomplete) { 784 dataSet.firePrimitivesRemoved(Collections.singletonList(this), true); 785 } else { 786 dataSet.firePrimitivesAdded(Collections.singletonList(this), true); 787 } 788 } 789 updateFlagsNoLock(FLAG_INCOMPLETE, incomplete); 790 } finally { 791 writeUnlock(locked); 792 } 728 793 } 729 794 … … 842 907 for (String key: keySet()) { 843 908 if (!isUninterestingKey(key)) { 844 updateFlags (FLAG_TAGGED, true);909 updateFlagsNoLock(FLAG_TAGGED, true); 845 910 return; 846 911 } 847 912 } 848 913 } 849 updateFlags (FLAG_TAGGED, false);914 updateFlagsNoLock(FLAG_TAGGED, false); 850 915 } 851 916 … … 871 936 } 872 937 873 updateFlags (FLAG_DIRECTION_REVERSED, directionReversed);874 updateFlags (FLAG_HAS_DIRECTIONS, hasDirections);938 updateFlagsNoLock(FLAG_DIRECTION_REVERSED, directionReversed); 939 updateFlagsNoLock(FLAG_HAS_DIRECTIONS, hasDirections); 875 940 } 876 941 … … 890 955 ------------*/ 891 956 957 // Note that all methods that read keys first make local copy of keys array reference. This is to ensure thread safety - reading 958 // doesn't have to be locked so it's possible that keys array will be modified. But all write methods make copy of keys array so 959 // the array itself will be never modified - only reference will be changed 960 892 961 /** 893 962 * The key/value list for this primitive. … … 901 970 * @return tags of this primitive. Changes made in returned map are not mapped 902 971 * back to the primitive, use setKeys() to modify the keys 903 * @since 1924904 972 */ 905 973 public Map<String, String> getKeys() { 906 974 Map<String, String> result = new HashMap<String, String>(); 975 String[] keys = this.keys; 907 976 if (keys != null) { 908 977 for (int i=0; i<keys.length ; i+=2) { … … 918 987 * 919 988 * @param keys the key/value pairs to set. If null, removes all existing key/value pairs. 920 * @since 1924921 989 */ 922 990 public void setKeys(Map<String, String> keys) { 923 Map<String, String> originalKeys = getKeys(); 924 if (keys == null || keys.isEmpty()) { 925 this.keys = null; 991 boolean locked = writeLock(); 992 try { 993 Map<String, String> originalKeys = getKeys(); 994 if (keys == null || keys.isEmpty()) { 995 this.keys = null; 996 keysChangedImpl(originalKeys); 997 return; 998 } 999 String[] newKeys = new String[keys.size() * 2]; 1000 int index = 0; 1001 for (Entry<String, String> entry:keys.entrySet()) { 1002 newKeys[index++] = entry.getKey(); 1003 newKeys[index++] = entry.getValue(); 1004 } 1005 this.keys = newKeys; 926 1006 keysChangedImpl(originalKeys); 927 return; 928 } 929 String[] newKeys = new String[keys.size() * 2]; 930 int index = 0; 931 for (Entry<String, String> entry:keys.entrySet()) { 932 newKeys[index++] = entry.getKey(); 933 newKeys[index++] = entry.getValue(); 934 } 935 this.keys = newKeys; 936 keysChangedImpl(originalKeys); 1007 } finally { 1008 writeUnlock(locked); 1009 } 937 1010 } 938 1011 … … 947 1020 */ 948 1021 public final void put(String key, String value) { 949 Map<String, String> originalKeys = getKeys(); 950 if (key == null) 951 return; 952 else if (value == null) { 953 remove(key); 954 } else if (keys == null){ 955 keys = new String[] {key, value}; 956 keysChangedImpl(originalKeys); 957 } else { 958 for (int i=0; i<keys.length;i+=2) { 959 if (keys[i].equals(key)) { 960 keys[i+1] = value; 961 keysChangedImpl(originalKeys); 962 return; 1022 boolean locked = writeLock(); 1023 try { 1024 Map<String, String> originalKeys = getKeys(); 1025 if (key == null) 1026 return; 1027 else if (value == null) { 1028 remove(key); 1029 } else if (keys == null){ 1030 keys = new String[] {key, value}; 1031 keysChangedImpl(originalKeys); 1032 } else { 1033 for (int i=0; i<keys.length;i+=2) { 1034 if (keys[i].equals(key)) { 1035 keys[i+1] = value; // This modifies the keys array but it doesn't make it invalidate for any time so its ok (see note no top) 1036 keysChangedImpl(originalKeys); 1037 return; 1038 } 963 1039 } 964 } 965 String[] newKeys = new String[keys.length + 2]; 966 for (int i=0; i< keys.length;i+=2) { 967 newKeys[i] = keys[i]; 968 newKeys[i+1] = keys[i+1]; 969 } 970 newKeys[keys.length] = key; 971 newKeys[keys.length + 1] = value; 1040 String[] newKeys = new String[keys.length + 2]; 1041 for (int i=0; i< keys.length;i+=2) { 1042 newKeys[i] = keys[i]; 1043 newKeys[i+1] = keys[i+1]; 1044 } 1045 newKeys[keys.length] = key; 1046 newKeys[keys.length + 1] = value; 1047 keys = newKeys; 1048 keysChangedImpl(originalKeys); 1049 } 1050 } finally { 1051 writeUnlock(locked); 1052 } 1053 } 1054 /** 1055 * Remove the given key from the list 1056 * 1057 * @param key the key to be removed. Ignored, if key is null. 1058 */ 1059 public final void remove(String key) { 1060 boolean locked = writeLock(); 1061 try { 1062 if (key == null || keys == null) return; 1063 if (!hasKey(key)) 1064 return; 1065 Map<String, String> originalKeys = getKeys(); 1066 if (keys.length == 2) { 1067 keys = null; 1068 keysChangedImpl(originalKeys); 1069 return; 1070 } 1071 String[] newKeys = new String[keys.length - 2]; 1072 int j=0; 1073 for (int i=0; i < keys.length; i+=2) { 1074 if (!keys[i].equals(key)) { 1075 newKeys[j++] = keys[i]; 1076 newKeys[j++] = keys[i+1]; 1077 } 1078 } 972 1079 keys = newKeys; 973 1080 keysChangedImpl(originalKeys); 974 } 975 } 976 /** 977 * Remove the given key from the list 978 * 979 * @param key the key to be removed. Ignored, if key is null. 980 */ 981 public final void remove(String key) { 982 if (key == null || keys == null) return; 983 if (!hasKey(key)) 984 return; 985 Map<String, String> originalKeys = getKeys(); 986 if (keys.length == 2) { 987 keys = null; 988 keysChangedImpl(originalKeys); 989 return; 990 } 991 String[] newKeys = new String[keys.length - 2]; 992 int j=0; 993 for (int i=0; i < keys.length; i+=2) { 994 if (!keys[i].equals(key)) { 995 newKeys[j++] = keys[i]; 996 newKeys[j++] = keys[i+1]; 997 } 998 } 999 keys = newKeys; 1000 keysChangedImpl(originalKeys); 1081 } finally { 1082 writeUnlock(locked); 1083 } 1001 1084 } 1002 1085 … … 1007 1090 */ 1008 1091 public final void removeAll() { 1009 if (keys != null) { 1010 Map<String, String> originalKeys = getKeys(); 1011 keys = null; 1012 keysChangedImpl(originalKeys); 1092 boolean locked = writeLock(); 1093 try { 1094 if (keys != null) { 1095 Map<String, String> originalKeys = getKeys(); 1096 keys = null; 1097 keysChangedImpl(originalKeys); 1098 } 1099 } finally { 1100 writeUnlock(locked); 1013 1101 } 1014 1102 } … … 1022 1110 */ 1023 1111 public final String get(String key) { 1112 String[] keys = this.keys; 1024 1113 if (key == null) 1025 1114 return null; … … 1033 1122 1034 1123 public final Collection<String> keySet() { 1124 String[] keys = this.keys; 1035 1125 if (keys == null) 1036 1126 return Collections.emptySet(); … … 1068 1158 */ 1069 1159 public boolean hasKey(String key) { 1160 String[] keys = this.keys; 1070 1161 if (key == null) return false; 1071 1162 if (keys == null) return false; … … 1166 1257 // when way is cloned 1167 1258 checkDataset(); 1259 Object referrers = this.referrers; 1168 1260 List<OsmPrimitive> result = new ArrayList<OsmPrimitive>(); 1169 1261 if (referrers != null) { … … 1202 1294 */ 1203 1295 public void cloneFrom(OsmPrimitive other) { 1296 // write lock is provided by subclasses 1204 1297 if (id != other.id && dataSet != null) 1205 1298 throw new DataIntegrityProblemException("Osm id cannot be changed after primitive was added to the dataset"); … … 1240 1333 */ 1241 1334 public void mergeFrom(OsmPrimitive other) { 1242 CheckParameterUtil.ensureParameterNotNull(other, "other"); 1243 if (other.isNew() ^ isNew()) 1244 throw new DataIntegrityProblemException(tr("Cannot merge because either of the participating primitives is new and the other is not")); 1245 if (! other.isNew() && other.getId() != id) 1246 throw new DataIntegrityProblemException(tr("Cannot merge primitives with different ids. This id is {0}, the other is {1}", id, other.getId())); 1247 1248 setKeys(other.getKeys()); 1249 timestamp = other.timestamp; 1250 version = other.version; 1251 setIncomplete(other.isIncomplete()); 1252 flags = other.flags; 1253 user= other.user; 1254 changesetId = other.changesetId; 1335 boolean locked = writeLock(); 1336 try { 1337 CheckParameterUtil.ensureParameterNotNull(other, "other"); 1338 if (other.isNew() ^ isNew()) 1339 throw new DataIntegrityProblemException(tr("Cannot merge because either of the participating primitives is new and the other is not")); 1340 if (! other.isNew() && other.getId() != id) 1341 throw new DataIntegrityProblemException(tr("Cannot merge primitives with different ids. This id is {0}, the other is {1}", id, other.getId())); 1342 1343 setKeys(other.getKeys()); 1344 timestamp = other.timestamp; 1345 version = other.version; 1346 setIncomplete(other.isIncomplete()); 1347 flags = other.flags; 1348 user= other.user; 1349 changesetId = other.changesetId; 1350 } finally { 1351 writeUnlock(locked); 1352 } 1255 1353 } 1256 1354 … … 1313 1411 */ 1314 1412 public String getName() { 1315 if (get("name") != null) 1316 return get("name"); 1317 return null; 1413 return get("name"); 1318 1414 } 1319 1415 … … 1356 1452 */ 1357 1453 public void load(PrimitiveData data) { 1454 // Write lock is provided by subclasses 1358 1455 setKeys(data.getKeys()); 1359 1456 setTimestamp(data.getTimestamp()); -
trunk/src/org/openstreetmap/josm/data/osm/Relation.java
r3347 r3348 38 38 */ 39 39 public void setMembers(List<RelationMember> members) { 40 for (RelationMember rm:this.members) { 41 rm.getMember().removeReferrer(this); 42 } 43 44 if (members != null) { 45 this.members = members.toArray(new RelationMember[members.size()]); 46 } 47 for (RelationMember rm:this.members) { 48 rm.getMember().addReferrer(this); 49 } 50 51 fireMembersChanged(); 40 boolean locked = writeLock(); 41 try { 42 for (RelationMember rm:this.members) { 43 rm.getMember().removeReferrer(this); 44 } 45 46 if (members != null) { 47 this.members = members.toArray(new RelationMember[members.size()]); 48 } 49 for (RelationMember rm:this.members) { 50 rm.getMember().addReferrer(this); 51 } 52 53 fireMembersChanged(); 54 } finally { 55 writeUnlock(locked); 56 } 52 57 } 53 58 … … 64 69 65 70 public void addMember(RelationMember member) { 66 RelationMember[] newMembers = new RelationMember[members.length + 1]; 67 System.arraycopy(members, 0, newMembers, 0, members.length); 68 newMembers[members.length] = member; 69 members = newMembers; 70 member.getMember().addReferrer(this); 71 fireMembersChanged(); 71 boolean locked = writeLock(); 72 try { 73 RelationMember[] newMembers = new RelationMember[members.length + 1]; 74 System.arraycopy(members, 0, newMembers, 0, members.length); 75 newMembers[members.length] = member; 76 members = newMembers; 77 member.getMember().addReferrer(this); 78 fireMembersChanged(); 79 } finally { 80 writeUnlock(locked); 81 } 72 82 } 73 83 74 84 public void addMember(int index, RelationMember member) { 75 RelationMember[] newMembers = new RelationMember[members.length + 1]; 76 System.arraycopy(members, 0, newMembers, 0, index); 77 System.arraycopy(members, index, newMembers, index + 1, members.length - index); 78 newMembers[index] = member; 79 members = newMembers; 80 member.getMember().addReferrer(this); 81 fireMembersChanged(); 85 boolean locked = writeLock(); 86 try { 87 RelationMember[] newMembers = new RelationMember[members.length + 1]; 88 System.arraycopy(members, 0, newMembers, 0, index); 89 System.arraycopy(members, index, newMembers, index + 1, members.length - index); 90 newMembers[index] = member; 91 members = newMembers; 92 member.getMember().addReferrer(this); 93 fireMembersChanged(); 94 } finally { 95 writeUnlock(locked); 96 } 82 97 } 83 98 … … 89 104 */ 90 105 public RelationMember setMember(int index, RelationMember member) { 91 RelationMember originalMember = members[index]; 92 members[index] = member; 93 if (originalMember.getMember() != member.getMember()) { 94 member.getMember().addReferrer(this); 95 originalMember.getMember().removeReferrer(this); 96 fireMembersChanged(); 97 } 98 return originalMember; 106 boolean locked = writeLock(); 107 try { 108 RelationMember originalMember = members[index]; 109 members[index] = member; 110 if (originalMember.getMember() != member.getMember()) { 111 member.getMember().addReferrer(this); 112 originalMember.getMember().removeReferrer(this); 113 fireMembersChanged(); 114 } 115 return originalMember; 116 } finally { 117 writeUnlock(locked); 118 } 99 119 } 100 120 … … 105 125 */ 106 126 public RelationMember removeMember(int index) { 107 List<RelationMember> members = getMembers(); 108 RelationMember result = members.remove(index); 109 setMembers(members); 110 return result; 127 boolean locked = writeLock(); 128 try { 129 List<RelationMember> members = getMembers(); 130 RelationMember result = members.remove(index); 131 setMembers(members); 132 return result; 133 } finally { 134 writeUnlock(locked); 135 } 111 136 } 112 137 … … 162 187 163 188 @Override public void cloneFrom(OsmPrimitive osm) { 164 super.cloneFrom(osm); 165 // It's not necessary to clone members as RelationMember class is immutable 166 setMembers(((Relation)osm).getMembers()); 189 boolean locked = writeLock(); 190 try { 191 super.cloneFrom(osm); 192 // It's not necessary to clone members as RelationMember class is immutable 193 setMembers(((Relation)osm).getMembers()); 194 } finally { 195 writeUnlock(locked); 196 } 167 197 } 168 198 169 199 @Override public void load(PrimitiveData data) { 170 super.load(data); 171 172 RelationData relationData = (RelationData) data; 173 174 List<RelationMember> newMembers = new ArrayList<RelationMember>(); 175 for (RelationMemberData member : relationData.getMembers()) { 176 OsmPrimitive primitive = getDataSet().getPrimitiveById(member); 177 if (primitive == null) 178 throw new AssertionError("Data consistency problem - relation with missing member detected"); 179 newMembers.add(new RelationMember(member.getRole(), primitive)); 180 } 181 setMembers(newMembers); 200 boolean locked = writeLock(); 201 try { 202 super.load(data); 203 204 RelationData relationData = (RelationData) data; 205 206 List<RelationMember> newMembers = new ArrayList<RelationMember>(); 207 for (RelationMemberData member : relationData.getMembers()) { 208 OsmPrimitive primitive = getDataSet().getPrimitiveById(member); 209 if (primitive == null) 210 throw new AssertionError("Data consistency problem - relation with missing member detected"); 211 newMembers.add(new RelationMember(member.getRole(), primitive)); 212 } 213 setMembers(newMembers); 214 } finally { 215 writeUnlock(locked); 216 } 182 217 } 183 218 … … 228 263 public RelationMember firstMember() { 229 264 if (isIncomplete()) return null; 265 266 RelationMember[] members = this.members; 230 267 return (members.length == 0) ? null : members[0]; 231 268 } 232 269 public RelationMember lastMember() { 233 270 if (isIncomplete()) return null; 271 272 RelationMember[] members = this.members; 234 273 return (members.length == 0) ? null : members[members.length - 1]; 235 274 } … … 244 283 return; 245 284 246 List<RelationMember> todelete = new ArrayList<RelationMember>(); 247 for (RelationMember member: members) { 248 if (member.getMember() == primitive) { 249 todelete.add(member); 250 } 251 } 252 List<RelationMember> members = getMembers(); 253 members.removeAll(todelete); 254 setMembers(members); 285 boolean locked = writeLock(); 286 try { 287 List<RelationMember> todelete = new ArrayList<RelationMember>(); 288 for (RelationMember member: members) { 289 if (member.getMember() == primitive) { 290 todelete.add(member); 291 } 292 } 293 List<RelationMember> members = getMembers(); 294 members.removeAll(todelete); 295 setMembers(members); 296 } finally { 297 writeUnlock(locked); 298 } 255 299 } 256 300 257 301 @Override 258 302 public void setDeleted(boolean deleted) { 259 for (RelationMember rm:members) { 260 if (deleted) { 261 rm.getMember().removeReferrer(this); 262 } else { 263 rm.getMember().addReferrer(this); 264 } 265 } 266 super.setDeleted(deleted); 303 boolean locked = writeLock(); 304 try { 305 for (RelationMember rm:members) { 306 if (deleted) { 307 rm.getMember().removeReferrer(this); 308 } else { 309 rm.getMember().addReferrer(this); 310 } 311 } 312 super.setDeleted(deleted); 313 } finally { 314 writeUnlock(locked); 315 } 267 316 } 268 317 … … 276 325 return; 277 326 278 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>(); 279 for (RelationMember member: members) { 280 if (primitives.contains(member.getMember())) { 281 todelete.add(member); 282 } 283 } 284 List<RelationMember> members = getMembers(); 285 members.removeAll(todelete); 286 setMembers(members); 327 boolean locked = writeLock(); 328 try { 329 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>(); 330 for (RelationMember member: members) { 331 if (primitives.contains(member.getMember())) { 332 todelete.add(member); 333 } 334 } 335 List<RelationMember> members = getMembers(); 336 members.removeAll(todelete); 337 setMembers(members); 338 } finally { 339 writeUnlock(locked); 340 } 287 341 } 288 342 … … 301 355 public Set<OsmPrimitive> getMemberPrimitives() { 302 356 HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>(); 357 RelationMember[] members = this.members; 303 358 for (RelationMember m: members) { 304 359 if (m.getMember() != null) { … … 315 370 @Override 316 371 public BBox getBBox() { 372 RelationMember[] members = this.members; 373 317 374 if (members.length == 0) 318 375 return new BBox(0, 0, 0, 0); … … 334 391 return null; 335 392 visitedRelations.add(this); 393 394 RelationMember[] members = this.members; 336 395 if (members.length == 0) 337 396 return null; … … 367 426 DataSet dataSet = getDataSet(); 368 427 if (dataSet != null) { 428 RelationMember[] members = this.members; 369 429 for (RelationMember rm: members) { 370 430 if (rm.getMember().getDataSet() != dataSet) … … 393 453 */ 394 454 public boolean hasIncompleteMembers() { 455 RelationMember[] members = this.members; 395 456 for (RelationMember rm: members) { 396 457 if (rm.getMember().isIncomplete()) return true; … … 407 468 public Collection<OsmPrimitive> getIncompleteMembers() { 408 469 Set<OsmPrimitive> ret = new HashSet<OsmPrimitive>(); 470 RelationMember[] members = this.members; 409 471 for (RelationMember rm: members) { 410 472 if (!rm.getMember().isIncomplete()) { -
trunk/src/org/openstreetmap/josm/data/osm/Way.java
r3254 r3348 47 47 */ 48 48 public void setNodes(List<Node> nodes) { 49 for (Node node:this.nodes) { 50 node.removeReferrer(this); 51 } 52 53 if (nodes == null) { 54 this.nodes = new Node[0]; 55 } else { 56 this.nodes = nodes.toArray(new Node[nodes.size()]); 57 } 58 for (Node node:this.nodes) { 59 node.addReferrer(this); 60 } 61 62 clearCached(); 63 fireNodesChanged(); 49 boolean locked = writeLock(); 50 try { 51 for (Node node:this.nodes) { 52 node.removeReferrer(this); 53 } 54 55 if (nodes == null) { 56 this.nodes = new Node[0]; 57 } else { 58 this.nodes = nodes.toArray(new Node[nodes.size()]); 59 } 60 for (Node node:this.nodes) { 61 node.addReferrer(this); 62 } 63 64 clearCached(); 65 fireNodesChanged(); 66 } finally { 67 writeUnlock(locked); 68 } 64 69 } 65 70 … … 98 103 public boolean containsNode(Node node) { 99 104 if (node == null) return false; 105 106 Node[] nodes = this.nodes; 100 107 for (int i=0; i<nodes.length; i++) { 101 108 if (nodes[i].equals(node)) … … 115 122 } 116 123 117 public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) {118 ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>();124 public List<Pair<Node,Node>> getNodePairs(boolean sort) { 125 List<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>(); 119 126 if (isIncomplete()) return chunkSet; 120 127 Node lastN = null; 121 for (Node n : this.nodes) { 128 Node[] nodes = this.nodes; 129 for (Node n : nodes) { 122 130 if (lastN == null) { 123 131 lastN = n; … … 198 206 @Override 199 207 public void load(PrimitiveData data) { 200 super.load(data); 201 202 WayData wayData = (WayData) data; 203 204 List<Node> newNodes = new ArrayList<Node>(wayData.getNodes().size()); 205 for (Long nodeId : wayData.getNodes()) { 206 Node node = (Node)getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE); 207 if (node != null) { 208 newNodes.add(node); 209 } else 210 throw new AssertionError("Data consistency problem - way with missing node detected"); 211 } 212 setNodes(newNodes); 208 boolean locked = writeLock(); 209 try { 210 super.load(data); 211 212 WayData wayData = (WayData) data; 213 214 List<Node> newNodes = new ArrayList<Node>(wayData.getNodes().size()); 215 for (Long nodeId : wayData.getNodes()) { 216 Node node = (Node)getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE); 217 if (node != null) { 218 newNodes.add(node); 219 } else 220 throw new AssertionError("Data consistency problem - way with missing node detected"); 221 } 222 setNodes(newNodes); 223 } finally { 224 writeUnlock(locked); 225 } 213 226 } 214 227 … … 223 236 224 237 @Override public void cloneFrom(OsmPrimitive osm) { 225 super.cloneFrom(osm); 226 Way otherWay = (Way)osm; 227 setNodes(otherWay.getNodes()); 238 boolean locked = writeLock(); 239 try { 240 super.cloneFrom(osm); 241 Way otherWay = (Way)osm; 242 setNodes(otherWay.getNodes()); 243 } finally { 244 writeUnlock(locked); 245 } 228 246 } 229 247 … … 256 274 public void removeNode(Node n) { 257 275 if (isIncomplete()) return; 258 boolean closed = (lastNode() == n && firstNode() == n); 259 int i; 260 List<Node> copy = getNodes(); 261 while ((i = copy.indexOf(n)) >= 0) { 262 copy.remove(i); 263 } 264 i = copy.size(); 265 if (closed && i > 2) { 266 copy.add(copy.get(0)); 267 } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) { 268 copy.remove(i-1); 269 } 270 setNodes(copy); 276 boolean locked = writeLock(); 277 try { 278 boolean closed = (lastNode() == n && firstNode() == n); 279 int i; 280 List<Node> copy = getNodes(); 281 while ((i = copy.indexOf(n)) >= 0) { 282 copy.remove(i); 283 } 284 i = copy.size(); 285 if (closed && i > 2) { 286 copy.add(copy.get(0)); 287 } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) { 288 copy.remove(i-1); 289 } 290 setNodes(copy); 291 } finally { 292 writeUnlock(locked); 293 } 271 294 } 272 295 273 296 public void removeNodes(Collection<? extends OsmPrimitive> selection) { 274 297 if (isIncomplete()) return; 275 for(OsmPrimitive p : selection) { 276 if (p instanceof Node) { 277 removeNode((Node)p); 278 } 298 boolean locked = writeLock(); 299 try { 300 for(OsmPrimitive p : selection) { 301 if (p instanceof Node) { 302 removeNode((Node)p); 303 } 304 } 305 } finally { 306 writeUnlock(locked); 279 307 } 280 308 } … … 289 317 public void addNode(Node n) throws IllegalStateException { 290 318 if (n==null) return; 291 if (isIncomplete()) 292 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId())); 293 clearCached(); 294 n.addReferrer(this); 295 Node[] newNodes = new Node[nodes.length + 1]; 296 System.arraycopy(nodes, 0, newNodes, 0, nodes.length); 297 newNodes[nodes.length] = n; 298 nodes = newNodes; 299 fireNodesChanged(); 319 320 boolean locked = writeLock(); 321 try { 322 if (isIncomplete()) 323 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId())); 324 clearCached(); 325 n.addReferrer(this); 326 Node[] newNodes = new Node[nodes.length + 1]; 327 System.arraycopy(nodes, 0, newNodes, 0, nodes.length); 328 newNodes[nodes.length] = n; 329 nodes = newNodes; 330 fireNodesChanged(); 331 } finally { 332 writeUnlock(locked); 333 } 300 334 } 301 335 … … 311 345 public void addNode(int offs, Node n) throws IllegalStateException, IndexOutOfBoundsException { 312 346 if (n==null) return; 313 if (isIncomplete()) 314 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId())); 315 clearCached(); 316 n.addReferrer(this); 317 Node[] newNodes = new Node[nodes.length + 1]; 318 System.arraycopy(nodes, 0, newNodes, 0, offs); 319 System.arraycopy(nodes, offs, newNodes, offs + 1, nodes.length - offs); 320 newNodes[offs] = n; 321 nodes = newNodes; 322 fireNodesChanged(); 347 348 boolean locked = writeLock(); 349 try { 350 if (isIncomplete()) 351 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId())); 352 353 clearCached(); 354 n.addReferrer(this); 355 Node[] newNodes = new Node[nodes.length + 1]; 356 System.arraycopy(nodes, 0, newNodes, 0, offs); 357 System.arraycopy(nodes, offs, newNodes, offs + 1, nodes.length - offs); 358 newNodes[offs] = n; 359 nodes = newNodes; 360 fireNodesChanged(); 361 } finally { 362 writeUnlock(locked); 363 } 323 364 } 324 365 325 366 @Override 326 367 public void setDeleted(boolean deleted) { 327 for (Node n:nodes) { 328 if (deleted) { 329 n.removeReferrer(this); 330 } else { 331 n.addReferrer(this); 332 } 333 } 334 fireNodesChanged(); 335 super.setDeleted(deleted); 368 boolean locked = writeLock(); 369 try { 370 for (Node n:nodes) { 371 if (deleted) { 372 n.removeReferrer(this); 373 } else { 374 n.addReferrer(this); 375 } 376 } 377 fireNodesChanged(); 378 super.setDeleted(deleted); 379 } finally { 380 writeUnlock(locked); 381 } 336 382 } 337 383 338 384 public boolean isClosed() { 339 385 if (isIncomplete()) return false; 340 return nodes.length >= 3 && lastNode() == firstNode(); 386 387 Node[] nodes = this.nodes; 388 return nodes.length >= 3 && nodes[nodes.length-1] == nodes[0]; 341 389 } 342 390 343 391 public Node lastNode() { 392 Node[] nodes = this.nodes; 344 393 if (isIncomplete() || nodes.length == 0) return null; 345 394 return nodes[nodes.length-1]; … … 347 396 348 397 public Node firstNode() { 398 Node[] nodes = this.nodes; 349 399 if (isIncomplete() || nodes.length == 0) return null; 350 400 return nodes[0]; … … 352 402 353 403 public boolean isFirstLastNode(Node n) { 404 Node[] nodes = this.nodes; 354 405 if (isIncomplete() || nodes.length == 0) return false; 355 return n == firstNode() || n == lastNode();406 return n == nodes[0] || n == nodes[nodes.length -1]; 356 407 } 357 408 … … 368 419 DataSet dataSet = getDataSet(); 369 420 if (dataSet != null) { 421 Node[] nodes = this.nodes; 370 422 for (Node n: nodes) { 371 423 if (n.getDataSet() != dataSet) … … 412 464 413 465 public boolean hasIncompleteNodes() { 466 Node[] nodes = this.nodes; 414 467 for (Node node:nodes) { 415 468 if (node.isIncomplete()) -
trunk/test/performance/org/openstreetmap/josm/data/osm/MapPaintVisitorPeformanceTest.java
r3167 r3348 4 4 import java.awt.Graphics2D; 5 5 import java.awt.image.BufferedImage; 6 import java.io.File;7 6 import java.io.FileInputStream; 8 9 import javax.imageio.ImageIO;10 7 11 8 import org.junit.BeforeClass; … … 63 60 visitor.visitAll(ds, true, bounds); 64 61 } 65 ImageIO.write(img, "png", new File("/home/jirka/a.png"));66 62 } 67 63
Note:
See TracChangeset
for help on using the changeset viewer.