Changeset 3348 in josm for trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
- Timestamp:
- 2010-06-27T17:07:49+02:00 (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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());
Note:
See TracChangeset
for help on using the changeset viewer.