KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > ecore > resource > impl > ResourceImpl


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 2002-2004 IBM Corporation and others.
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors:
11  * IBM - Initial API and implementation
12  *
13  * </copyright>
14  *
15  * $Id: ResourceImpl.java,v 1.9 2005/06/08 06:20:10 nickb Exp $
16  */

17 package org.eclipse.emf.ecore.resource.impl;
18
19
20 import java.io.IOException JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.ListIterator JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.zip.ZipEntry JavaDoc;
30 import java.util.zip.ZipInputStream JavaDoc;
31 import java.util.zip.ZipOutputStream JavaDoc;
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 /**
56  * A highly extensible resource implementation.
57  * <p>
58  * The following configuration and control mechanisms are provided:
59  * <ul>
60  * <li><b>Serialization</b></li>
61  * <ul>
62  * <li>{@link #doSave(OutputStream, Map)}</li>
63  * <li>{@link #doLoad(InputStream, Map)}</li>
64  * <li>{@link #doUnload}</li>
65  * </ul>
66  * <li><b>Root URI Fragment</b></li>
67  * <ul>
68  * <li>{@link #getURIFragmentRootSegment(EObject)}</li>
69  * <li>{@link #getEObjectForURIFragmentRootSegment(String)}</li>
70  * </ul>
71  * <li><b>Containment Changes</b></li>
72  * <ul>
73  * <li>{@link #attached(EObject)}</li>
74  * <li>{@link #detached(EObject)}</li>
75  * <li>{@link #unloaded(InternalEObject)}</li>
76  * </ul>
77  * <li><b>ZIP</b></li>
78  * <ul>
79  * <li>{@link #useZip}</li>
80  * <li>{@link #newContentZipEntry}</li>
81  * <li>{@link #isContentZipEntry(ZipEntry)}</li>
82  * </ul>
83  * <li><b>URI Conversion</b></li>
84  * <ul>
85  * <li>{@link #getURIConverter}</li>
86  * </ul>
87  * <li><b>Modification</b></li>
88  * <ul>
89  * <li>{@link #createModificationTrackingAdapter()}</li>
90  * </ul>
91  * </ul>
92  * </p>
93  */

94 public class ResourceImpl extends NotifierImpl implements Resource, Resource.Internal
95 {
96   /**
97    * The default URI converter when there is no resource set.
98    */

99   private static URIConverter defaultURIConverter;
100
101   /**
102    * Returns the default URI converter that's used when there is no resource set.
103    * @return the default URI converter.
104    * @see #getURIConverter
105    */

106   protected static URIConverter getDefaultURIConverter()
107   {
108     if (defaultURIConverter == null)
109     {
110       defaultURIConverter = new URIConverterImpl();
111     }
112     return defaultURIConverter;
113   }
114
115   /**
116    * The storage for the default save options.
117    */

118   protected Map JavaDoc defaultSaveOptions;
119
120   /**
121    * The storage for the default load options.
122    */

123   protected Map JavaDoc defaultLoadOptions;
124
125   /**
126    * The containing resource set.
127    * @see #getResourceSet
128    */

129   protected ResourceSet resourceSet;
130
131   /**
132    * The URI.
133    * @see #getURI
134    */

135   protected URI uri;
136
137   /**
138    * The contents.
139    * @see #getContents
140    */

141   protected ContentsEList contents;
142
143   /**
144    * The errors.
145    * @see #getErrors
146    */

147   protected EList errors;
148
149   /**
150    * The warnings.
151    * @see #getErrors
152    */

153   protected EList warnings;
154
155   /**
156    * The modified flag.
157    * @see #isModified
158    */

159   protected boolean isModified;
160
161   /**
162    * The loaded flag.
163    * @see #isLoaded
164    */

165   protected boolean isLoaded;
166
167   /**
168    * The modification tracking adapter.
169    * @see #isTrackingModification
170    * @see #attached(EObject)
171    * @see #detached(EObject)
172    */

173   protected Adapter modificationTrackingAdapter;
174
175   /**
176    * A map to retrieve the EObject based on the value of its ID feature.
177    * @see #setIntrinsicIDToEObjectMap(Map)
178    */

179   protected Map JavaDoc intrinsicIDToEObjectMap;
180
181   /**
182    * Creates a empty instance.
183    */

184   public ResourceImpl()
185   {
186   }
187
188   /**
189    * Creates an instance with the given URI.
190    * @param uri the URI.
191    */

192   public ResourceImpl(URI uri)
193   {
194     this();
195     this.uri = uri;
196   }
197
198   /*
199    * Javadoc copied from interface.
200    */

201   public ResourceSet getResourceSet()
202   {
203     return resourceSet;
204   }
205
206   /**
207    * Sets the new containing resource set, and removes the resource from a previous containing resource set, if necessary.
208    * @param resourceSet the new containing resource set.
209    * @param notifications the accumulating notifications.
210    * @return notification of the change.
211    */

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 JavaDoc getNotifier()
232            {
233              return ResourceImpl.this;
234            }
235            public int getFeatureID(Class JavaDoc expectedClass)
236            {
237              return RESOURCE__RESOURCE_SET;
238            }
239          });
240     }
241
242     return notifications;
243   }
244
245   /*
246    * Javadoc copied from interface.
247    */

248   public URI getURI()
249   {
250     return uri;
251   }
252
253   /*
254    * Javadoc copied from interface.
255    */

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 JavaDoc getNotifier()
266           {
267             return ResourceImpl.this;
268           }
269           public int getFeatureID(Class JavaDoc expectedClass)
270           {
271             return RESOURCE__URI;
272           }
273         };
274       eNotify(notification);
275     }
276   }
277
278   /**
279    * A notifying list implementation for supporting {@link Resource#getContents}.
280    */

281   protected class ContentsEList extends NotifyingListImpl implements InternalEList
282   {
283     public Object JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc basicIterator()
332     {
333       return super.basicIterator();
334     }
335
336     public ListIterator JavaDoc basicListIterator()
337     {
338       return super.basicListIterator();
339     }
340   
341     public ListIterator JavaDoc basicListIterator(int index)
342     {
343       return super.basicListIterator(index);
344     }
345
346     public List JavaDoc basicList()
347     {
348       return super.basicList();
349     }
350
351     protected Object JavaDoc [] newData(int capacity)
352     {
353       return new EObject [capacity];
354     }
355
356     protected void didAdd(int index, Object JavaDoc object)
357     {
358       super.didAdd(index, object);
359       loaded();
360       modified();
361     }
362
363     protected void didRemove(int index, Object JavaDoc object)
364     {
365       super.didRemove(index, object);
366       modified();
367     }
368
369     protected void didSet(int index, Object JavaDoc newObject, Object JavaDoc oldObject)
370     {
371       super.didSet(index, newObject, oldObject);
372       modified();
373     }
374
375     protected void didClear(int oldSize, Object JavaDoc [] 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   /*
409    * Javadoc copied from interface.
410    */

411   public EList getContents()
412   {
413     if (contents == null)
414     {
415       contents = new ContentsEList();
416     }
417     return contents;
418   }
419
420   /*
421    * Javadoc copied from interface.
422    */

423   public TreeIterator getAllContents()
424   {
425     return
426       new AbstractTreeIterator(this, false)
427       {
428         public Iterator JavaDoc getChildren(Object JavaDoc object)
429         {
430           return object == ResourceImpl.this ? ResourceImpl.this.getContents().iterator() : ((EObject)object).eContents().iterator();
431         }
432       };
433   }
434
435   /*
436    * Javadoc copied from interface.
437    */

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 JavaDoc 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   /*
465    * Javadoc copied from interface.
466    */

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 JavaDoc 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   /**
494    * Returns whether contents will be compressed.
495    * This implementation returns <code>false</code>.
496    * When this returns <code>true</code>,
497    * {@link #save(OutputStream, Map)} and {@link #load(InputStream, Map)}
498    * will zip compress and decompress contents.
499    * @return whether contents will be compressed.
500    * @see #newContentZipEntry
501    * @see #isContentZipEntry(ZipEntry)
502    */

503   protected boolean useZip()
504   {
505     return false;
506   }
507
508
509   /**
510    * Returns the URI fragment root segment for reaching the given direct content object.
511    * This default implementation returns the position of the object, if there is more than one object,
512    * otherwise, the empty string.
513    * As a result, the URI fragment for a single root object will be <code>"/"</code>.
514    * @return the URI fragment root segment for reaching the given direct content object.
515    */

516   protected String JavaDoc getURIFragmentRootSegment(EObject eObject)
517   {
518     List JavaDoc contents = getContents();
519     return contents.size() > 1 ?
520       Integer.toString(getContents().indexOf(eObject)) :
521       "";
522   }
523
524   /*
525    * Javadoc copied from interface.
526    */

527   public String JavaDoc getURIFragment(EObject eObject)
528   {
529     String JavaDoc id = EcoreUtil.getID(eObject);
530     if (id != null)
531     {
532       return id;
533     }
534     else
535     {
536       List JavaDoc uriFragmentPath = new ArrayList JavaDoc();
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 JavaDoc result = new StringBuffer JavaDoc("/");
544       result.append(getURIFragmentRootSegment(eObject));
545
546       for (ListIterator JavaDoc i = uriFragmentPath.listIterator(uriFragmentPath.size()); i.hasPrevious(); )
547       {
548         result.append('/');
549         result.append((String JavaDoc)i.previous());
550       }
551       return result.toString();
552     }
553   }
554
555   /**
556    * Returns the object associated with the URI fragment root segment.
557    * This default implementation uses the position of the object;
558    * an empty string is the same as <code>"0"</code>.
559    * @return the object associated with the URI fragment root segment.
560    */

561   protected EObject getEObjectForURIFragmentRootSegment(String JavaDoc uriFragmentRootSegment)
562   {
563     int position = 0;
564     if (uriFragmentRootSegment.length() > 0)
565     {
566       try
567       {
568         position = Integer.parseInt(uriFragmentRootSegment);
569       }
570       catch (NumberFormatException JavaDoc exception)
571       {
572         throw new WrappedException(exception);
573       }
574     }
575
576     List JavaDoc 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   /*
588    * Javadoc copied from interface.
589    */

590   public EObject getEObject(String JavaDoc uriFragment)
591   {
592     int length = uriFragment.length();
593     if (length > 0)
594     {
595       if (uriFragment.charAt(0) == '/')
596       {
597         ArrayList JavaDoc uriFragmentPath = new ArrayList JavaDoc(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   /**
624    * Returns the object based on the fragment path as a list of Strings.
625    */

626   protected EObject getEObject(List JavaDoc uriFragmentPath)
627   {
628     int size = uriFragmentPath.size();
629     EObject eObject = getEObjectForURIFragmentRootSegment(size == 0 ? "" : (String JavaDoc)uriFragmentPath.get(0));
630     for (int i = 1; i < size && eObject != null; ++i)
631     {
632       eObject = ((InternalEObject)eObject).eObjectForURIFragmentSegment((String JavaDoc)uriFragmentPath.get(i));
633     }
634
635     return eObject;
636   }
637
638   /**
639    * Returns the map used to cache the EObject that is identified by the {@link #getEObjectByID(String) value}
640    * of its ID feature.
641    * @return the map used to cache the EObject that is identified by the value of its ID feature.
642    * @see #setIntrinsicIDToEObjectMap
643    */

644   public Map JavaDoc getIntrinsicIDToEObjectMap()
645   {
646     return intrinsicIDToEObjectMap;
647   }
648
649   /**
650    * Sets the map used to cache the EObject identified by the value of its ID feature.
651    * This cache is only activated if the map is not <code>null</code>.
652    * The map will be lazily loaded by the {@link #getEObjectByID(String) getEObjectByID} method.
653    * It is up to the client to clear the cache when it becomes invalid,
654    * e.g., when the ID of a previously mapped EObject is changed.
655    * @param intrinsicIDToEObjectMap the new map or <code>null</code>.
656    * @see #getIntrinsicIDToEObjectMap
657    */

658   public void setIntrinsicIDToEObjectMap(Map JavaDoc intrinsicIDToEObjectMap)
659   {
660     this.intrinsicIDToEObjectMap = intrinsicIDToEObjectMap;
661   }
662   
663
664   /**
665    * Returns the object based on the fragment as an ID.
666    */

667   protected EObject getEObjectByID(String JavaDoc id)
668   {
669     Map JavaDoc 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 JavaDoc i = getAllContents(); i.hasNext(); )
680     {
681       EObject eObject = (EObject)i.next();
682       String JavaDoc 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 JavaDoc 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 JavaDoc map = getIntrinsicIDToEObjectMap();
725     if (map != null)
726     {
727       String JavaDoc id = EcoreUtil.getID(eObject);
728       if (id != null)
729       {
730         map.put(id, eObject);
731       }
732     }
733   }
734   
735
736   /**
737    * Adds modification tracking adapters to the object and it's content tree.
738    * @param eObject the object.
739    * @see #attached(EObject)
740    * @deprecated since 2.1.0. This method is not invoked anymore. See
741    * {@link #attachedHelper(EObject)}.
742    */

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 JavaDoc tree = eObject.eAllContents(); tree.hasNext(); )
753       {
754         detachedHelper((EObject)tree.next());
755       }
756     }
757   }
758   
759   protected void detachedHelper(EObject eObject)
760   {
761     Map JavaDoc map = getIntrinsicIDToEObjectMap();
762     if (map != null)
763     {
764       String JavaDoc 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   /**
778    * Removes modification tracking adapters to the object and it's content tree.
779    * @param eObject the object.
780    * @see #detached(EObject)
781    * @deprecated since 2.1.0. This method is not invoked anymore. See
782    * {@link #attachedHelper(EObject)}.
783    */

784   final protected void removeModificationTrackingAdapters(EObject eObject)
785   {
786   }
787
788
789   /**
790    * Returns the URI converter.
791    * This typically gets the {@link ResourceSet#getURIConverter converter}
792    * from the {@link #getResourceSet containing} resource set,
793    * but it calls {@link #getDefaultURIConverter} when there is no containing resource set.
794    * @return the URI converter.
795    */

796   protected URIConverter getURIConverter()
797   {
798     return
799       getResourceSet() == null ?
800         getDefaultURIConverter() :
801         getResourceSet().getURIConverter();
802   }
803
804   /*
805    * Javadoc copied from interface.
806    */

807   public void save(Map JavaDoc options) throws IOException JavaDoc
808   {
809     URIConverter uriConverter = getURIConverter();
810     OutputStream JavaDoc outputStream = uriConverter.createOutputStream(getURI());
811     try
812     {
813       save(outputStream, options);
814     }
815     finally
816     {
817       outputStream.close();
818     }
819   }
820
821   /*
822    * Javadoc copied from interface.
823    */

824   public void load(Map JavaDoc options) throws IOException JavaDoc
825   {
826     if (!isLoaded)
827     {
828       URIConverter uriConverter = getURIConverter();
829       InputStream JavaDoc inputStream = uriConverter.createInputStream(getURI());
830       try
831       {
832         load(inputStream, options);
833       }
834       finally
835       {
836         inputStream.close();
837       }
838     }
839   }
840
841   /**
842    * Returns a new zip entry for {@link #save(OutputStream, Map) saving} the resource contents.
843    * It is called by {@link #save(OutputStream, Map)} when writing {@link #useZip zipped} contents.
844    * This implementation creates an entry called <code>ResourceContents</code>.
845    * @return a new zip entry.
846    * @see #isContentZipEntry(ZipEntry)
847    */

848   protected ZipEntry JavaDoc newContentZipEntry()
849   {
850     return new ZipEntry JavaDoc("ResourceContents");
851   }
852
853   /**
854    * Saves the resource to the output stream using the specified options.
855    * <p>
856    * This implementation is <code>final</code>;
857    * clients should override {@link #doSave doSave}.
858    * </p>
859    * @param options the save options.
860    * @see #save(Map)
861    * @see #doSave(OutputStream, Map)
862    * @see #load(InputStream, Map)
863    */

864   public final void save(OutputStream JavaDoc outputStream, Map JavaDoc options) throws IOException JavaDoc
865   {
866     ZipOutputStream JavaDoc zipOutputStream = null;
867     if (useZip())
868     {
869       zipOutputStream =
870         new ZipOutputStream JavaDoc(outputStream)
871         {
872           public void flush()
873           {
874           }
875           public void close() throws IOException JavaDoc
876           {
877             try
878             {
879               super.flush();
880             }
881             catch (IOException JavaDoc 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 JavaDoc mergedOptions = new HashMap JavaDoc(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   /**
915    * Called to save the resource.
916    * This implementation throws an exception;
917    * clients must override it.
918    * @param outputStream the stream
919    * @param options the save options.
920    * @exception UnsupportedOperationException.
921    */

922   protected void doSave(OutputStream JavaDoc outputStream, Map JavaDoc options) throws IOException JavaDoc
923   {
924     throw new UnsupportedOperationException JavaDoc();
925   }
926
927   /**
928    * Returns whether the given entry is the content entry for this resource.
929    * It is called by {@link #load(InputStream, Map)} when reading {@link #useZip zipped} contents.
930    * This implementation return <code>true</code>;
931    * i.e., the first entry will be read.
932    * @return whether the given entry is the content entry for this resource.
933    * @see #newContentZipEntry
934    */

935   protected boolean isContentZipEntry(ZipEntry JavaDoc zipEntry)
936   {
937     return true;
938   }
939
940   /*
941    * Javadoc copied from interface.
942    */

943   public final void load(InputStream JavaDoc inputStream, Map JavaDoc options) throws IOException JavaDoc
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 JavaDoc zipInputStream = new ZipInputStream JavaDoc(inputStream);
962         while (zipInputStream.available() != 0)
963         {
964           ZipEntry JavaDoc 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 JavaDoc mergedOptions = new HashMap JavaDoc(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  /**
1004   * Called to load the resource.
1005   * This implementation throws an exception;
1006   * clients must override it.
1007   * @param inputStream the stream
1008   * @param options the load options.
1009   * @exception UnsupportedOperationException.
1010   */

1011  protected void doLoad(InputStream JavaDoc inputStream, Map JavaDoc options) throws IOException JavaDoc
1012  {
1013    throw new UnsupportedOperationException JavaDoc();
1014  }
1015
1016  /*
1017   * Javadoc copied from interface.
1018   */

1019  public boolean isLoaded()
1020  {
1021    return isLoaded;
1022  }
1023
1024  /**
1025   * Called when the object is unloaded.
1026   * This implementation
1027   * {@link InternalEObject#eSetProxyURI sets} the object to be a proxy
1028   * and clears the {@link #eAdapters adapters}.
1029   */

1030  protected void unloaded(InternalEObject internalEObject)
1031  {
1032    internalEObject.eSetProxyURI(uri.appendFragment(getURIFragment(internalEObject)));
1033    internalEObject.eAdapters().clear();
1034  }
1035
1036  /**
1037   * Sets the load state as indicated, and returns a notification, if {@link org.eclipse.emf.common.notify.impl.BasicNotifierImpl#eNotificationRequired required}.
1038   * Clients are <b>not</b> expected to call this directly; it is managed by the implementation.
1039   * @param isLoaded whether the resource is loaded.
1040   * @return a notification.
1041   */

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 JavaDoc getNotifier()
1053          {
1054            return ResourceImpl.this;
1055          }
1056          public int getFeatureID(Class JavaDoc expectedClass)
1057          {
1058            return RESOURCE__IS_LOADED;
1059          }
1060        };
1061      return notification;
1062    }
1063    else
1064    {
1065      return null;
1066    }
1067  }
1068
1069  /**
1070   * Does all the work of unloading the resource.
1071   * It calls {@link #unloaded unloaded} for each object it the content {@link #getAllContents tree},
1072   * and clears the {@link #getContents contents}, {@link #getErrors errors}, and {@link #getWarnings warnings}.
1073   */

1074  protected void doUnload()
1075  {
1076    Iterator JavaDoc allContents = EcoreUtil.getAllContents(new ArrayList JavaDoc(getContents()));
1077
1078    // This guard is needed to ensure that clear doesn't make the resource become loaded.
1079
//
1080
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  /*
1094   * Javadoc copied from interface.
1095   */

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  /**
1110   * An adapter implementation for tracking resource modification.
1111   */

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  /*
1141   * Javadoc copied from interface.
1142   */

1143  public boolean isTrackingModification()
1144  {
1145    return modificationTrackingAdapter != null;
1146  }
1147
1148  /*
1149   * Javadoc copied from interface.
1150   */

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 JavaDoc 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 JavaDoc 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 JavaDoc getNotifier()
1186          {
1187            return ResourceImpl.this;
1188          }
1189          public int getFeatureID(Class JavaDoc expectedClass)
1190          {
1191            return RESOURCE__IS_TRACKING_MODIFICATION;
1192          }
1193        };
1194      eNotify(notification);
1195    }
1196  }
1197
1198
1199  /**
1200   * Creates a modification tracking adapter.
1201   * This implementation creates a {@link ResourceImpl.ModificationTrackingAdapter}.
1202   * Clients may override this to any adapter.
1203   * @see #modificationTrackingAdapter
1204   * @see #isTrackingModification
1205   */

1206  protected Adapter createModificationTrackingAdapter()
1207  {
1208    return new ModificationTrackingAdapter();
1209  }
1210
1211  /*
1212   * Javadoc copied from interface.
1213   */

1214  public boolean isModified()
1215  {
1216    return isModified;
1217  }
1218
1219  /*
1220   * Javadoc copied from interface.
1221   */

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 JavaDoc getNotifier()
1232          {
1233            return ResourceImpl.this;
1234          }
1235          public int getFeatureID(Class JavaDoc expectedClass)
1236          {
1237            return RESOURCE__IS_MODIFIED;
1238          }
1239        };
1240      eNotify(notification);
1241    }
1242  }
1243
1244  /**
1245   * If an implementation uses IDs and stores the IDs as part of the resource
1246   * rather than as objects, this method should return a string representation of
1247   * the ID to object mapping, which might be implemented as a Java Map.
1248   * @return a string representation of the ID to object mapping
1249   */

1250  public String JavaDoc toKeyString()
1251  {
1252    StringBuffer JavaDoc result = new StringBuffer JavaDoc("Key type: ");
1253    result.append(getClass().toString());
1254    return result.toString();
1255  }
1256
1257  public String JavaDoc toString()
1258  {
1259    return
1260      getClass().getName() + '@' + Integer.toHexString(hashCode()) +
1261        " uri='" + uri + "'";
1262  }
1263}
1264
Popular Tags