1 17 package org.eclipse.emf.ecore.resource.impl; 18 19 20 import java.io.IOException ; 21 import java.io.InputStream ; 22 import java.io.OutputStream ; 23 import java.util.ArrayList ; 24 import java.util.HashMap ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.ListIterator ; 28 import java.util.Map ; 29 import java.util.zip.ZipEntry ; 30 import java.util.zip.ZipInputStream ; 31 import java.util.zip.ZipOutputStream ; 32 33 import org.eclipse.emf.common.notify.Adapter; 34 import org.eclipse.emf.common.notify.Notification; 35 import org.eclipse.emf.common.notify.NotificationChain; 36 import org.eclipse.emf.common.notify.impl.AdapterImpl; 37 import org.eclipse.emf.common.notify.impl.NotificationChainImpl; 38 import org.eclipse.emf.common.notify.impl.NotificationImpl; 39 import org.eclipse.emf.common.notify.impl.NotifierImpl; 40 import org.eclipse.emf.common.notify.impl.NotifyingListImpl; 41 import org.eclipse.emf.common.util.AbstractTreeIterator; 42 import org.eclipse.emf.common.util.EList; 43 import org.eclipse.emf.common.util.TreeIterator; 44 import org.eclipse.emf.common.util.URI; 45 import org.eclipse.emf.common.util.WrappedException; 46 import org.eclipse.emf.ecore.EObject; 47 import org.eclipse.emf.ecore.InternalEObject; 48 import org.eclipse.emf.ecore.resource.Resource; 49 import org.eclipse.emf.ecore.resource.ResourceSet; 50 import org.eclipse.emf.ecore.resource.URIConverter; 51 import org.eclipse.emf.ecore.util.EcoreUtil; 52 import org.eclipse.emf.ecore.util.InternalEList; 53 54 55 94 public class ResourceImpl extends NotifierImpl implements Resource, Resource.Internal 95 { 96 99 private static URIConverter defaultURIConverter; 100 101 106 protected static URIConverter getDefaultURIConverter() 107 { 108 if (defaultURIConverter == null) 109 { 110 defaultURIConverter = new URIConverterImpl(); 111 } 112 return defaultURIConverter; 113 } 114 115 118 protected Map defaultSaveOptions; 119 120 123 protected Map defaultLoadOptions; 124 125 129 protected ResourceSet resourceSet; 130 131 135 protected URI uri; 136 137 141 protected ContentsEList contents; 142 143 147 protected EList errors; 148 149 153 protected EList warnings; 154 155 159 protected boolean isModified; 160 161 165 protected boolean isLoaded; 166 167 173 protected Adapter modificationTrackingAdapter; 174 175 179 protected Map intrinsicIDToEObjectMap; 180 181 184 public ResourceImpl() 185 { 186 } 187 188 192 public ResourceImpl(URI uri) 193 { 194 this(); 195 this.uri = uri; 196 } 197 198 201 public ResourceSet getResourceSet() 202 { 203 return resourceSet; 204 } 205 206 212 public NotificationChain basicSetResourceSet(ResourceSet resourceSet, NotificationChain notifications) 213 { 214 ResourceSet oldResourceSet = this.resourceSet; 215 if (oldResourceSet != null) 216 { 217 notifications = ((InternalEList)oldResourceSet.getResources()).basicRemove(this, notifications); 218 } 219 220 this.resourceSet = resourceSet; 221 222 if (eNotificationRequired()) 223 { 224 if (notifications == null) 225 { 226 notifications = new NotificationChainImpl(2); 227 } 228 notifications.add 229 (new NotificationImpl(Notification.SET, oldResourceSet, resourceSet) 230 { 231 public Object getNotifier() 232 { 233 return ResourceImpl.this; 234 } 235 public int getFeatureID(Class expectedClass) 236 { 237 return RESOURCE__RESOURCE_SET; 238 } 239 }); 240 } 241 242 return notifications; 243 } 244 245 248 public URI getURI() 249 { 250 return uri; 251 } 252 253 256 public void setURI(URI uri) 257 { 258 URI oldURI = this.uri; 259 this.uri = uri; 260 if (eNotificationRequired()) 261 { 262 Notification notification = 263 new NotificationImpl(Notification.SET, oldURI, uri) 264 { 265 public Object getNotifier() 266 { 267 return ResourceImpl.this; 268 } 269 public int getFeatureID(Class expectedClass) 270 { 271 return RESOURCE__URI; 272 } 273 }; 274 eNotify(notification); 275 } 276 } 277 278 281 protected class ContentsEList extends NotifyingListImpl implements InternalEList 282 { 283 public Object getNotifier() 284 { 285 return ResourceImpl.this; 286 } 287 288 public int getFeatureID() 289 { 290 return RESOURCE__CONTENTS; 291 } 292 293 protected boolean isNotificationRequired() 294 { 295 return ResourceImpl.this.eNotificationRequired(); 296 } 297 298 protected boolean useEquals() 299 { 300 return false; 301 } 302 303 protected boolean hasInverse() 304 { 305 return true; 306 } 307 308 protected boolean isUnique() 309 { 310 return true; 311 } 312 313 public NotificationChain inverseAdd(Object object, NotificationChain notifications) 314 { 315 InternalEObject eObject = (InternalEObject)object; 316 notifications = eObject.eSetResource(ResourceImpl.this, notifications); 317 ResourceImpl.this.attached(eObject); 318 return notifications; 319 } 320 321 public NotificationChain inverseRemove(Object object, NotificationChain notifications) 322 { 323 InternalEObject eObject = (InternalEObject)object; 324 if (ResourceImpl.this.isLoaded) 325 { 326 ResourceImpl.this.detached(eObject); 327 } 328 return eObject.eSetResource(null, notifications); 329 } 330 331 public Iterator basicIterator() 332 { 333 return super.basicIterator(); 334 } 335 336 public ListIterator basicListIterator() 337 { 338 return super.basicListIterator(); 339 } 340 341 public ListIterator basicListIterator(int index) 342 { 343 return super.basicListIterator(index); 344 } 345 346 public List basicList() 347 { 348 return super.basicList(); 349 } 350 351 protected Object [] newData(int capacity) 352 { 353 return new EObject [capacity]; 354 } 355 356 protected void didAdd(int index, Object object) 357 { 358 super.didAdd(index, object); 359 loaded(); 360 modified(); 361 } 362 363 protected void didRemove(int index, Object object) 364 { 365 super.didRemove(index, object); 366 modified(); 367 } 368 369 protected void didSet(int index, Object newObject, Object oldObject) 370 { 371 super.didSet(index, newObject, oldObject); 372 modified(); 373 } 374 375 protected void didClear(int oldSize, Object [] oldData) 376 { 377 if (oldSize == 0) 378 { 379 loaded(); 380 } 381 else 382 { 383 super.didClear(oldSize, oldData); 384 } 385 } 386 387 protected void loaded() 388 { 389 if (!ResourceImpl.this.isLoaded()) 390 { 391 Notification notification = ResourceImpl.this.setLoaded(true); 392 if (notification != null) 393 { 394 ResourceImpl.this.eNotify(notification); 395 } 396 } 397 } 398 399 protected void modified() 400 { 401 if (isTrackingModification()) 402 { 403 setModified(true); 404 } 405 } 406 } 407 408 411 public EList getContents() 412 { 413 if (contents == null) 414 { 415 contents = new ContentsEList(); 416 } 417 return contents; 418 } 419 420 423 public TreeIterator getAllContents() 424 { 425 return 426 new AbstractTreeIterator(this, false) 427 { 428 public Iterator getChildren(Object object) 429 { 430 return object == ResourceImpl.this ? ResourceImpl.this.getContents().iterator() : ((EObject)object).eContents().iterator(); 431 } 432 }; 433 } 434 435 438 public EList getErrors() 439 { 440 if (errors == null) 441 { 442 errors = 443 new NotifyingListImpl() 444 { 445 protected boolean isNotificationRequired() 446 { 447 return ResourceImpl.this.eNotificationRequired(); 448 } 449 450 public Object getNotifier() 451 { 452 return ResourceImpl.this; 453 } 454 455 public int getFeatureID() 456 { 457 return RESOURCE__ERRORS; 458 } 459 }; 460 } 461 return errors; 462 } 463 464 467 public EList getWarnings() 468 { 469 if (warnings == null) 470 { 471 warnings = 472 new NotifyingListImpl() 473 { 474 protected boolean isNotificationRequired() 475 { 476 return ResourceImpl.this.eNotificationRequired(); 477 } 478 479 public Object getNotifier() 480 { 481 return ResourceImpl.this; 482 } 483 484 public int getFeatureID() 485 { 486 return RESOURCE__WARNINGS; 487 } 488 }; 489 } 490 return warnings; 491 } 492 493 503 protected boolean useZip() 504 { 505 return false; 506 } 507 508 509 516 protected String getURIFragmentRootSegment(EObject eObject) 517 { 518 List contents = getContents(); 519 return contents.size() > 1 ? 520 Integer.toString(getContents().indexOf(eObject)) : 521 ""; 522 } 523 524 527 public String getURIFragment(EObject eObject) 528 { 529 String id = EcoreUtil.getID(eObject); 530 if (id != null) 531 { 532 return id; 533 } 534 else 535 { 536 List uriFragmentPath = new ArrayList (); 537 for (EObject container = eObject.eContainer(); container != null; container = eObject.eContainer()) 538 { 539 uriFragmentPath.add(((InternalEObject)container).eURIFragmentSegment(eObject.eContainingFeature(), eObject)); 540 eObject = container; 541 } 542 543 StringBuffer result = new StringBuffer ("/"); 544 result.append(getURIFragmentRootSegment(eObject)); 545 546 for (ListIterator i = uriFragmentPath.listIterator(uriFragmentPath.size()); i.hasPrevious(); ) 547 { 548 result.append('/'); 549 result.append((String )i.previous()); 550 } 551 return result.toString(); 552 } 553 } 554 555 561 protected EObject getEObjectForURIFragmentRootSegment(String uriFragmentRootSegment) 562 { 563 int position = 0; 564 if (uriFragmentRootSegment.length() > 0) 565 { 566 try 567 { 568 position = Integer.parseInt(uriFragmentRootSegment); 569 } 570 catch (NumberFormatException exception) 571 { 572 throw new WrappedException(exception); 573 } 574 } 575 576 List contents = getContents(); 577 if (position < contents.size()) 578 { 579 return (EObject)contents.get(position); 580 } 581 else 582 { 583 return null; 584 } 585 } 586 587 590 public EObject getEObject(String uriFragment) 591 { 592 int length = uriFragment.length(); 593 if (length > 0) 594 { 595 if (uriFragment.charAt(0) == '/') 596 { 597 ArrayList uriFragmentPath = new ArrayList (4); 598 int start = 1; 599 for (int i = 1; i < length; ++i) 600 { 601 if (uriFragment.charAt(i) == '/') 602 { 603 uriFragmentPath.add(start == i ? "" : uriFragment.substring(start, i)); 604 start = i + 1; 605 } 606 } 607 uriFragmentPath.add(uriFragment.substring(start)); 608 return getEObject(uriFragmentPath); 609 } 610 else if (uriFragment.charAt(length - 1) == '?') 611 { 612 int index = uriFragment.lastIndexOf('?', length - 2); 613 if (index > 0) 614 { 615 uriFragment = uriFragment.substring(0, index); 616 } 617 } 618 } 619 620 return getEObjectByID(uriFragment); 621 } 622 623 626 protected EObject getEObject(List uriFragmentPath) 627 { 628 int size = uriFragmentPath.size(); 629 EObject eObject = getEObjectForURIFragmentRootSegment(size == 0 ? "" : (String )uriFragmentPath.get(0)); 630 for (int i = 1; i < size && eObject != null; ++i) 631 { 632 eObject = ((InternalEObject)eObject).eObjectForURIFragmentSegment((String )uriFragmentPath.get(i)); 633 } 634 635 return eObject; 636 } 637 638 644 public Map getIntrinsicIDToEObjectMap() 645 { 646 return intrinsicIDToEObjectMap; 647 } 648 649 658 public void setIntrinsicIDToEObjectMap(Map intrinsicIDToEObjectMap) 659 { 660 this.intrinsicIDToEObjectMap = intrinsicIDToEObjectMap; 661 } 662 663 664 667 protected EObject getEObjectByID(String id) 668 { 669 Map map = getIntrinsicIDToEObjectMap(); 670 if (map != null) 671 { 672 EObject eObject = (EObject)map.get(id); 673 if (eObject != null) 674 { 675 return eObject; 676 } 677 } 678 679 for (Iterator i = getAllContents(); i.hasNext(); ) 680 { 681 EObject eObject = (EObject)i.next(); 682 String eObjectId = EcoreUtil.getID(eObject); 683 if (eObjectId != null) 684 { 685 if (map != null) 686 { 687 map.put(eObjectId, eObject); 688 } 689 690 if (eObjectId.equals(id)) 691 { 692 return eObject; 693 } 694 } 695 } 696 697 return null; 698 } 699 700 public void attached(EObject eObject) 701 { 702 if (isAttachedDetachedHelperRequired()) 703 { 704 attachedHelper(eObject); 705 for (Iterator tree = eObject.eAllContents(); tree.hasNext(); ) 706 { 707 attachedHelper((EObject)tree.next()); 708 } 709 } 710 } 711 712 protected boolean isAttachedDetachedHelperRequired() 713 { 714 return isTrackingModification() || getIntrinsicIDToEObjectMap() != null; 715 } 716 717 protected void attachedHelper(EObject eObject) 718 { 719 if (isTrackingModification()) 720 { 721 eObject.eAdapters().add(modificationTrackingAdapter); 722 } 723 724 Map map = getIntrinsicIDToEObjectMap(); 725 if (map != null) 726 { 727 String id = EcoreUtil.getID(eObject); 728 if (id != null) 729 { 730 map.put(id, eObject); 731 } 732 } 733 } 734 735 736 743 final protected void addModificationTrackingAdapters(EObject eObject) 744 { 745 } 746 747 public void detached(EObject eObject) 748 { 749 if (isAttachedDetachedHelperRequired()) 750 { 751 detachedHelper(eObject); 752 for (Iterator tree = eObject.eAllContents(); tree.hasNext(); ) 753 { 754 detachedHelper((EObject)tree.next()); 755 } 756 } 757 } 758 759 protected void detachedHelper(EObject eObject) 760 { 761 Map map = getIntrinsicIDToEObjectMap(); 762 if (map != null) 763 { 764 String id = EcoreUtil.getID(eObject); 765 if (id != null) 766 { 767 map.remove(id); 768 } 769 } 770 771 if (isTrackingModification()) 772 { 773 eObject.eAdapters().remove(modificationTrackingAdapter); 774 } 775 } 776 777 784 final protected void removeModificationTrackingAdapters(EObject eObject) 785 { 786 } 787 788 789 796 protected URIConverter getURIConverter() 797 { 798 return 799 getResourceSet() == null ? 800 getDefaultURIConverter() : 801 getResourceSet().getURIConverter(); 802 } 803 804 807 public void save(Map options) throws IOException 808 { 809 URIConverter uriConverter = getURIConverter(); 810 OutputStream outputStream = uriConverter.createOutputStream(getURI()); 811 try 812 { 813 save(outputStream, options); 814 } 815 finally 816 { 817 outputStream.close(); 818 } 819 } 820 821 824 public void load(Map options) throws IOException 825 { 826 if (!isLoaded) 827 { 828 URIConverter uriConverter = getURIConverter(); 829 InputStream inputStream = uriConverter.createInputStream(getURI()); 830 try 831 { 832 load(inputStream, options); 833 } 834 finally 835 { 836 inputStream.close(); 837 } 838 } 839 } 840 841 848 protected ZipEntry newContentZipEntry() 849 { 850 return new ZipEntry ("ResourceContents"); 851 } 852 853 864 public final void save(OutputStream outputStream, Map options) throws IOException 865 { 866 ZipOutputStream zipOutputStream = null; 867 if (useZip()) 868 { 869 zipOutputStream = 870 new ZipOutputStream (outputStream) 871 { 872 public void flush() 873 { 874 } 875 public void close() throws IOException 876 { 877 try 878 { 879 super.flush(); 880 } 881 catch (IOException exception) 882 { 883 } 884 super.close(); 885 } 886 }; 887 zipOutputStream.putNextEntry(newContentZipEntry()); 888 outputStream = zipOutputStream; 889 } 890 891 if (defaultSaveOptions == null || defaultSaveOptions.isEmpty()) 892 { 893 doSave(outputStream, options); 894 } 895 else if (options == null) 896 { 897 doSave(outputStream, defaultSaveOptions); 898 } 899 else 900 { 901 Map mergedOptions = new HashMap (defaultSaveOptions); 902 mergedOptions.putAll(options); 903 904 doSave(outputStream, mergedOptions); 905 } 906 907 setModified(false); 908 if (zipOutputStream != null) 909 { 910 zipOutputStream.finish(); 911 } 912 } 913 914 922 protected void doSave(OutputStream outputStream, Map options) throws IOException 923 { 924 throw new UnsupportedOperationException (); 925 } 926 927 935 protected boolean isContentZipEntry(ZipEntry zipEntry) 936 { 937 return true; 938 } 939 940 943 public final void load(InputStream inputStream, Map options) throws IOException 944 { 945 if (!isLoaded) 946 { 947 Notification notification = setLoaded(true); 948 949 if (errors != null) 950 { 951 errors.clear(); 952 } 953 954 if (warnings != null) 955 { 956 warnings.clear(); 957 } 958 959 if (useZip()) 960 { 961 ZipInputStream zipInputStream = new ZipInputStream (inputStream); 962 while (zipInputStream.available() != 0) 963 { 964 ZipEntry zipEntry = zipInputStream.getNextEntry(); 965 if (isContentZipEntry(zipEntry)) 966 { 967 inputStream = zipInputStream; 968 break; 969 } 970 } 971 } 972 973 try 974 { 975 if (defaultLoadOptions == null || defaultLoadOptions.isEmpty()) 976 { 977 doLoad(inputStream, options); 978 } 979 else if (options == null) 980 { 981 doLoad(inputStream, defaultLoadOptions); 982 } 983 else 984 { 985 Map mergedOptions = new HashMap (defaultLoadOptions); 986 mergedOptions.putAll(options); 987 988 doLoad(inputStream, mergedOptions); 989 } 990 } 991 finally 992 { 993 if (notification != null) 994 { 995 eNotify(notification); 996 } 997 998 setModified(false); 999 } 1000 } 1001 } 1002 1003 1011 protected void doLoad(InputStream inputStream, Map options) throws IOException 1012 { 1013 throw new UnsupportedOperationException (); 1014 } 1015 1016 1019 public boolean isLoaded() 1020 { 1021 return isLoaded; 1022 } 1023 1024 1030 protected void unloaded(InternalEObject internalEObject) 1031 { 1032 internalEObject.eSetProxyURI(uri.appendFragment(getURIFragment(internalEObject))); 1033 internalEObject.eAdapters().clear(); 1034 } 1035 1036 1042 protected Notification setLoaded(boolean isLoaded) 1043 { 1044 boolean oldIsLoaded = this.isLoaded; 1045 this.isLoaded = isLoaded; 1046 1047 if (eNotificationRequired()) 1048 { 1049 Notification notification = 1050 new NotificationImpl(Notification.SET, oldIsLoaded, isLoaded) 1051 { 1052 public Object getNotifier() 1053 { 1054 return ResourceImpl.this; 1055 } 1056 public int getFeatureID(Class expectedClass) 1057 { 1058 return RESOURCE__IS_LOADED; 1059 } 1060 }; 1061 return notification; 1062 } 1063 else 1064 { 1065 return null; 1066 } 1067 } 1068 1069 1074 protected void doUnload() 1075 { 1076 Iterator allContents = EcoreUtil.getAllContents(new ArrayList (getContents())); 1077 1078 if (!getContents().isEmpty()) 1081 { 1082 getContents().clear(); 1083 } 1084 getErrors().clear(); 1085 getWarnings().clear(); 1086 1087 while (allContents.hasNext()) 1088 { 1089 unloaded((InternalEObject)allContents.next()); 1090 } 1091 } 1092 1093 1096 public final void unload() 1097 { 1098 if (isLoaded) 1099 { 1100 Notification notification = setLoaded(false); 1101 doUnload(); 1102 if (notification != null) 1103 { 1104 eNotify(notification); 1105 } 1106 } 1107 } 1108 1109 1112 protected class ModificationTrackingAdapter extends AdapterImpl 1113 { 1114 public void notifyChanged(Notification notification) 1115 { 1116 switch (notification.getEventType()) 1117 { 1118 case Notification.SET: 1119 case Notification.UNSET: 1120 case Notification.MOVE: 1121 { 1122 if (!notification.isTouch()) 1123 { 1124 setModified(true); 1125 } 1126 break; 1127 } 1128 case Notification.ADD: 1129 case Notification.REMOVE: 1130 case Notification.ADD_MANY: 1131 case Notification.REMOVE_MANY: 1132 { 1133 setModified(true); 1134 break; 1135 } 1136 } 1137 } 1138 } 1139 1140 1143 public boolean isTrackingModification() 1144 { 1145 return modificationTrackingAdapter != null; 1146 } 1147 1148 1151 public void setTrackingModification(boolean isTrackingModification) 1152 { 1153 boolean oldIsTrackingModification = modificationTrackingAdapter != null; 1154 1155 if (oldIsTrackingModification != isTrackingModification) 1156 { 1157 if (isTrackingModification) 1158 { 1159 modificationTrackingAdapter = createModificationTrackingAdapter(); 1160 1161 for (Iterator i = getAllContents(); i.hasNext(); ) 1162 { 1163 EObject eObject = (EObject)i.next(); 1164 eObject.eAdapters().add(modificationTrackingAdapter); 1165 } 1166 } 1167 else 1168 { 1169 Adapter oldModificationTrackingAdapter = modificationTrackingAdapter; 1170 modificationTrackingAdapter = null; 1171 1172 for (Iterator i = getAllContents(); i.hasNext(); ) 1173 { 1174 EObject eObject = (EObject)i.next(); 1175 eObject.eAdapters().remove(oldModificationTrackingAdapter); 1176 } 1177 } 1178 } 1179 1180 if (eNotificationRequired()) 1181 { 1182 Notification notification = 1183 new NotificationImpl(Notification.SET, oldIsTrackingModification, isTrackingModification) 1184 { 1185 public Object getNotifier() 1186 { 1187 return ResourceImpl.this; 1188 } 1189 public int getFeatureID(Class expectedClass) 1190 { 1191 return RESOURCE__IS_TRACKING_MODIFICATION; 1192 } 1193 }; 1194 eNotify(notification); 1195 } 1196 } 1197 1198 1199 1206 protected Adapter createModificationTrackingAdapter() 1207 { 1208 return new ModificationTrackingAdapter(); 1209 } 1210 1211 1214 public boolean isModified() 1215 { 1216 return isModified; 1217 } 1218 1219 1222 public void setModified(boolean isModified) 1223 { 1224 boolean oldIsModified = this.isModified; 1225 this.isModified = isModified; 1226 if (eNotificationRequired()) 1227 { 1228 Notification notification = 1229 new NotificationImpl(Notification.SET, oldIsModified, isModified) 1230 { 1231 public Object getNotifier() 1232 { 1233 return ResourceImpl.this; 1234 } 1235 public int getFeatureID(Class expectedClass) 1236 { 1237 return RESOURCE__IS_MODIFIED; 1238 } 1239 }; 1240 eNotify(notification); 1241 } 1242 } 1243 1244 1250 public String toKeyString() 1251 { 1252 StringBuffer result = new StringBuffer ("Key type: "); 1253 result.append(getClass().toString()); 1254 return result.toString(); 1255 } 1256 1257 public String toString() 1258 { 1259 return 1260 getClass().getName() + '@' + Integer.toHexString(hashCode()) + 1261 " uri='" + uri + "'"; 1262 } 1263} 1264 | Popular Tags |