Author: tfmorris
Date: 2010-04-15 10:53:16-0700
New Revision: 18269

Modified:
   trunk/src/argouml-app/tests/org/argouml/persistence/TestXmiFilePersister.java
   trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/FacadeMDRImpl.java
   
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/MDRModelImplementation.java
   
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/ModelEventPumpMDRImpl.java
   trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java
   
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java
   
trunk/src/argouml-core-model-mdr/tests/org/argouml/model/mdr/AbstractMDRModelImplementationTestCase.java

Log:
RESOLVED - task 6008: Stereotypes defined in profile dont't stay applied after 
save and reload 
http://argouml.tigris.org/issues/show_bug.cgi?id=6008

Modified: 
trunk/src/argouml-app/tests/org/argouml/persistence/TestXmiFilePersister.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/persistence/TestXmiFilePersister.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-app/tests/org/argouml/persistence/TestXmiFilePersister.java   
    (original)
+++ 
trunk/src/argouml-app/tests/org/argouml/persistence/TestXmiFilePersister.java   
    2010-04-15 10:53:16-0700
@@ -156,7 +156,6 @@
         
         persister = new XmiFilePersister();
         project = persister.doLoad(file);
-        ProjectManager.getManager().setCurrentProject(project);
         
         Object attType = checkFoo(project.findType("Foo", false));
 

Modified: 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/FacadeMDRImpl.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/FacadeMDRImpl.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/FacadeMDRImpl.java   
    (original)
+++ 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/FacadeMDRImpl.java   
    2010-04-15 10:53:16-0700
@@ -1,6 +1,6 @@
 /* $Id$
  
*******************************************************************************
- * Copyright (c) 2010 Contributors - see below
+ * Copyright (c) 2005,2010 Contributors - see below
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -4127,12 +4127,7 @@
                 if (ref == null) {
                     return mofId;
                 } else {
-                    String systemId = ref.getSystemId();
-                    if (systemId == null || systemId.equals("")) {
-                        return ref.getXmiId();
-                    } else {
-                        return systemId + "#" + ref.getXmiId();
-                    }
+                    return ref.getXmiId();
                 }
             }
         } catch (InvalidObjectException e) {

Modified: 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/MDRModelImplementation.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/MDRModelImplementation.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/MDRModelImplementation.java
      (original)
+++ 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/MDRModelImplementation.java
      2010-04-15 10:53:16-0700
@@ -1,13 +1,13 @@
 /* $Id$
  *****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2005,2010 Contributors - see below
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
- *    tfmorris
+ *    Tom Morris
  *****************************************************************************
  *
  * Some portions of this file was previously release using the BSD License:
@@ -52,6 +52,7 @@
 import javax.jmi.model.ModelPackage;
 import javax.jmi.model.MofPackage;
 import javax.jmi.reflect.InvalidObjectException;
+import javax.jmi.reflect.RefObject;
 import javax.jmi.reflect.RefPackage;
 import javax.jmi.xmi.MalformedXMIException;
 
@@ -191,6 +192,12 @@
      */
     private Map<String, String> public2SystemIds = 
         Collections.synchronizedMap(new HashMap<String, String>());
+    
+    /**
+     * Index of objects keyed by system ID, then xmi.id within that file
+     */
+    private Map<String, Map<String, Object>> idToObject = 
+        Collections.synchronizedMap(new HashMap<String, Map<String, 
Object>>());
 
     private List<String> searchDirs = new ArrayList<String>();
     
@@ -198,9 +205,32 @@
     /**
      * Set of extents and their read-only status. 
      */
-    private Map<UmlPackage, Boolean> extents = 
-        new HashMap<UmlPackage, Boolean>(10, (float) .5);
+    private Map<UmlPackage, Extent> extents = 
+        new HashMap<UmlPackage, Extent>(10, (float) .5);
 
+    private class Extent {
+        int refCount = 0;
+        boolean readOnly = false;
+        String name;
+        
+        Extent(String name, boolean readOnly) {
+            this.name = name;
+            this.readOnly = readOnly;
+        }
+        
+        int getRefCount() {
+            return refCount;
+        }
+        
+        synchronized int decrementCount() {
+            return refCount--;
+        }
+        
+        synchronized int incrementCount() {
+            return refCount++;
+        }
+    }
+    
     /**
      * @return Returns the root UML Factory package for user model.
      * @deprecated for 0.26. Use RefObject.refOutermostPackage instead if at 
all
@@ -222,8 +252,8 @@
             synchronized (extents) {
                 UmlPackage extent = (UmlPackage) getRepository().createExtent(
                         name, getMofPackage());
-                extents.put(extent, Boolean.valueOf(readOnly));
-
+                extents.put(extent, new Extent(name,readOnly));
+                
                 if (!readOnly) {
                     // TODO: This will need to change when we support multiple
                     // user models.
@@ -252,6 +282,22 @@
         }
     }
 
+
+    /**
+     * Delete all extents except those for the UML metamodel and the 
+     * meta-meta model (ie MOF).
+     */
+    private void cleanExtents() {
+        String[] names = repository.getExtentNames();
+        for (String n : names) {
+            if (!MOF_EXTENT_NAME.equals(n) && !"MOF".equals(n)) {
+                RefPackage extent = repository.getExtent(n);
+                extent.refDelete();
+                LOG.debug("Deleting extent " + n);
+            }
+        }
+    }
+    
     void deleteExtent(UmlPackage extent) {
         synchronized (extents) {
             if (umlPackage.equals(extent)) {
@@ -267,8 +313,34 @@
 
     private void deleteExtentUnchecked(UmlPackage extent) {
         synchronized (extents) {
-            extents.remove(extent);
-            extent.refDelete();
+            Extent e = extents.get(extent);
+            if (e == null) {
+                LOG.warn("No listing for extent " + extent);
+                extent.refDelete();
+            } else {
+                if (e.decrementCount() == 0) {
+
+                    String name = extents.remove(extent).name;
+                    if (public2SystemIds.remove(name) == null) {
+                        if (!"model extent".equals(name)) {
+                            LOG.warn("No system id found for extent "
+                                    + (name == null ? "" : name) + " : "
+                                    + extent);
+                        }
+                    }
+                    if (idToObject.remove(name) == null) {
+                        if (!"model extent".equals(name)) {
+                            LOG.warn("No ID map found for extent "
+                                    + (name == null ? "" : name) + " : "
+                                    + extent);
+                        }
+                    }
+                    // TODO: Need to clean up objectToId
+                    // (can we do it based on modelelement delete
+                    // notifications?)
+                    extent.refDelete();
+                }
+            }
         }
     }
     
@@ -278,12 +350,12 @@
     
     boolean isReadOnly(Object extent) {
         synchronized (extents) {
-            Boolean result = extents.get(extent);
+            Extent result = extents.get(extent);
             if (result == null) {
-                LOG.warn("Unable to find extent " + extent);
+//                LOG.warn("Unable to find extent " + extent);
                 return false;
-            }
-            return result.booleanValue();
+            } 
+            return result.readOnly;
         }
     }
     
@@ -347,6 +419,7 @@
     public MDRModelImplementation() throws UmlException {
         this(getDefaultRepository());
 
+        cleanExtents();
         createDefaultExtent();
         if (umlPackage == null) {
             throw new UmlException("Could not create UML extent");
@@ -774,14 +847,55 @@
     }
 
     /**
-     * Return the Object to ID Map.
+     * Return map of MOF ID to XmiReference (system id + xmi.id).
      *
      * @return the map
      */
-    protected Map<String, XmiReference> getObjectToId() {
+    Map<String, XmiReference> getObjectToId() {
         return objectToId;
     }
+
+    /**
+     * Return map of maps keyed first by system id, then xmi.id with object as
+     * value.
+     * 
+     * @return the map
+     */
+    Map<String, Map<String, Object>> getIdToObject() {
+        return idToObject;
+    }
+    
+    /**
+     * Remove an element from indexes mapping it back to its original xmi.id.
+     * 
+     * @param mofId MOF ID of element to be removed from indexes
+     * @return false if no index entries were removed
+     */
+    boolean removeElement(String mofId) {
+        XmiReference xref = objectToId.remove(mofId);
+        if (xref != null) {
+            Map<String,Object> m = idToObject.get(xref.getSystemId());
+            if (m != null) {
+                Object o = m.remove(xref.getXmiId());
+                if (o != null) {
+                    if (!mofId.equals(((RefObject) o).refMofId())) {
+                        LOG.error("Internal index inconsistency for mof ID " 
+                                + mofId + " (got " + ((RefObject) 
o).refMofId());
+                    }
+                    return true;
+                }
+            }
+        }
+        // Elements created after file load won't have index entries
+        LOG.debug("Failed to remove index entries for mof ID " + mofId);
+        return false;
+    }
     
+    /**
+     * Return map of MOF ID to XmiReference (system id + xmi.id).
+     *
+     * @return the map
+     */
     Map<String, String> getPublic2SystemIds() {
         return public2SystemIds;
     }

Modified: 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/ModelEventPumpMDRImpl.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/ModelEventPumpMDRImpl.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/ModelEventPumpMDRImpl.java
       (original)
+++ 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/ModelEventPumpMDRImpl.java
       2010-04-15 10:53:16-0700
@@ -284,6 +284,9 @@
             InstanceEvent ie = (InstanceEvent) mdrEvent;
             events.add(new DeleteInstanceEvent(ie.getSource(),
                     "remove", null, null, mdrEvent));
+            // Clean up index entries
+            String mofid = ((InstanceEvent)mdrEvent).getInstance().refMofId();
+            modelImpl.removeElement(mofid);
         } else if (mdrEvent instanceof AssociationEvent) {
             AssociationEvent ae = (AssociationEvent) mdrEvent;
             if (ae.isOfType(AssociationEvent.EVENT_ASSOCIATION_ADD)) {

Modified: 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java   
    (original)
+++ 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java   
    2010-04-15 10:53:16-0700
@@ -148,9 +148,9 @@
         
         Collection<RefObject> newElements = Collections.emptyList();
 
-        String extentBase = inputSource.getSystemId();
+        String extentBase = inputSource.getPublicId();
         if (extentBase == null) {
-            extentBase = inputSource.getPublicId();
+            extentBase = inputSource.getSystemId();
         }
         if (extentBase == null) {
             extentBase = MDRModelImplementation.MODEL_EXTENT_NAME;
@@ -178,11 +178,29 @@
             config.setUnknownElementsListener(this);
             config.setUnknownElementsIgnored(true);
 
+            String pId = inputSource.getPublicId();
+            String sId = modelImpl.getPublic2SystemIds().get(pId);
+            if (sId != null) {
+                if (sId.equals(inputSource.getSystemId())) {
+                    LOG.info("Attempt to reread profile - ignoring - "
+                            + "publicId = \"" + pId + "\";  systemId = \""
+                            + sId + "\".");
+                    return Collections.emptySet();
+                } else {
+                    throw new UmlException("Profile with the duplicate 
publicId "
+                            + "is being loaded! publicId = \"" + pId
+                            + "\"; existing systemId = \""
+                            + modelImpl.getPublic2SystemIds().get(pId)
+                            + "\"; new systemId = \"" + sId + "\".");
+                }
+            }
             resolver = new XmiReferenceResolverImpl(new RefPackage[] {extent},
                     config, modelImpl.getObjectToId(), 
-                    modelImpl.getPublic2SystemIds(), 
modelImpl.getSearchPath(), 
+                    modelImpl.getPublic2SystemIds(), 
modelImpl.getIdToObject(), 
+                    modelImpl.getSearchPath(), 
                     readOnly, 
-                    inputSource.getPublicId(), inputSource.getSystemId());
+                    inputSource.getPublicId(), inputSource.getSystemId(),
+                    modelImpl);
             config.setReferenceResolver(resolver);
             config.setHeaderConsumer(this);
             
@@ -228,7 +246,9 @@
                         || inputSource.getCharacterStream() != null) {
                     File file = copySource(inputSource);
                     systemId = file.toURI().toURL().toExternalForm();
+                    String publicId = inputSource.getPublicId();
                     inputSource = new InputSource(systemId);
+                    inputSource.setPublicId(publicId);                    
                 }
                 MDRepository repository = modelImpl.getRepository();
                 
@@ -343,6 +363,7 @@
         // InputSource xformedInput = chainedTransform(transformFiles, pIs);
         InputSource xformedInput = serialTransform(transformFiles,
                 input);
+        xformedInput.setPublicId(input.getPublicId());
         return xmiReader.read(xformedInput.getByteStream(), xformedInput
                 .getSystemId(), extent);
     }
@@ -468,6 +489,7 @@
                 myInput =
                     new SAXSource(new InputSource(new FileInputStream(
                         tmpOutFile)));
+                
myInput.setSystemId(tmpOutFile.toURI().toURL().toExternalForm());
             }
             return myInput.getInputSource();
         } catch (IOException e) {

Modified: 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java
    (original)
+++ 
trunk/src/argouml-core-model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java
    2010-04-15 10:53:16-0700
@@ -1,12 +1,13 @@
 /* $Id$
  *****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2005,2010 Contributors - see below
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
+ *    Tom Morris
  *    euluis
  *****************************************************************************
  *
@@ -56,11 +57,12 @@
 import javax.jmi.reflect.RefPackage;
 
 import org.apache.log4j.Logger;
+import org.argouml.model.UmlException;
 import org.argouml.model.XmiReferenceRuntimeException;
 import org.netbeans.api.xmi.XMIInputConfig;
 import org.netbeans.lib.jmi.util.DebugException;
 import org.netbeans.lib.jmi.xmi.XmiContext;
-import org.omg.uml.foundation.core.ModelElement;
+import org.xml.sax.InputSource;
 
 /**
  * Custom resolver to use with XMI reader.
@@ -71,7 +73,12 @@
  * <li>Records the mapping of <code>xmi.id</code>'s to MDR objects as they
  * are resolved so that the map can be used to lookup objects by xmi.id later
  * (used by diagram subsystem to associate GEF/PGML objects with model
- * elements).
+ * elements).  This map is also used to resolve cross references (HREFs) to 
+ * other files when reading multiple files linked together.
+ * <li>Keeps an inverse map of objects to the xmi.id that they were read in 
from
+ * which can be used to maintain stable xmi.id values on output.
+ * <li>Handles search special processing for profiles including the search list
+ * of directories which an be used to look them up.
  * <li>Resolves a System ID to a fully specified URL which can be used by MDR
  * to open and read the referenced content. The standard MDR resolver is
  * extended to support that "jar:" protocol for URLs, allowing it to handle
@@ -93,13 +100,17 @@
     private static final Logger LOG =
         Logger.getLogger(XmiReferenceResolverImpl.class);
     
-    private Map<String, Object> idToObjects = 
-        Collections.synchronizedMap(new HashMap<String, Object>());
+    /**
+     * Map of href/id to object.  IDs for top level document will have no
+     * leading URL piece while others will be in <url>#<id> form
+     */
+    private Map<String, Map<String, Object>> idToObject = 
+        Collections.synchronizedMap(new HashMap<String, Map<String, 
Object>>());
 
     /**
-     * Map indexed by MOF ID.
+     * Map indexed by MOF ID containing XmiReference objects.
      */
-    private Map<String, XmiReference> objectsToId;
+    private Map<String, XmiReference> mofidToXmiref;
 
     /**
      * System ID of top level document
@@ -107,6 +118,11 @@
     private String topSystemId;
 
     /**
+     * Most recent system ID (public ID in our context) translated by toURL
+     */
+    private Map<String, URL> pendingProfiles = new HashMap<String, URL>();
+    
+    /**
      * URI form of topSystemID for use in relativization.
      */
     private URI baseUri;
@@ -128,18 +144,26 @@
     private Map<String, URL> urlMap = new HashMap<String, URL>();
     
     /**
-     * Mapping from URL or absolute reference back to the original SystemID
+     * Mapping from absolute resolved URL to the original SystemID
      * that was read from the input file.  We'll preserve this mapping when
      * we write things back out again.
      */
     private Map<String, String> reverseUrlMap = new HashMap<String, String>();
     
+    /**
+     * True if top level file is a profile/readonly
+     */
     private boolean profile;
 
+    /**
+     * Mapping from public ID to system ID for files which have been read.
+     */
     private Map<String, String> public2SystemIds;
 
     private String modelPublicId;
 
+    private MDRModelImplementation modelImpl;
+
     /**
      * Constructor.
      * @param systemId 
@@ -148,23 +172,39 @@
      */
     // CHECKSTYLE:OFF - ignore too many parameters since API is fixed by MDR
     XmiReferenceResolverImpl(RefPackage[] extents, XMIInputConfig config,
-            Map<String, XmiReference> objectToIdMap, 
-            Map<String, String> publicIds, List<String> searchDirs, 
-            boolean isProfile, String publicId, String systemId) {
+            Map<String, XmiReference> objectToXmiref, 
+            Map<String, String> publicIds, 
+            Map<String, Map<String, Object>> idToObject, 
+            List<String> searchDirs,
+            boolean isProfile, String publicId, String systemId,
+            MDRModelImplementation modelImplementation) {
     // CHECKSTYLE:ON
         super(extents, config);
-        objectsToId = objectToIdMap;
+        modelImpl = modelImplementation;
+        mofidToXmiref = objectToXmiref;
         modulesPath = searchDirs;
         profile = isProfile;
         public2SystemIds = publicIds;
+        this.idToObject = idToObject;
         modelPublicId = publicId;
         if (isProfile) {
+            if (publicId == null) {
+                LOG.warn("Profile load with null public ID.  Using system ID - 
"
+                        + systemId);
+                modelPublicId = publicId = systemId;
+            }
             if (public2SystemIds.containsKey(modelPublicId)) {
-                LOG.warn("Either an already loaded profile is being re-read " 
-                    + "or a profile with the same publicId is being loaded! " 
-                    + "publicId = \"" + publicId + "\"; existing systemId = \""
-                    + public2SystemIds.get(publicId) + "\"; new systemId = \"" 
-                    + systemId + "\".");
+                if (systemId.equals(public2SystemIds.get(publicId))) {
+                    LOG.warn("Loaded profile is being re-read "
+                            + "publicId = \"" + publicId + "\";  systemId = \""
+                            + systemId + "\".");
+                } else {
+                    LOG.warn("Profile with the duplicate publicId "
+                            + "is being loaded! publicId = \"" + publicId
+                            + "\"; existing systemId = \""
+                            + public2SystemIds.get(publicId)
+                            + "\"; new systemId = \"" + systemId + "\".");
+                }
             }
             public2SystemIds.put(publicId, systemId);
         }
@@ -207,67 +247,107 @@
         String resolvedSystemId = systemId;
         if (profile && systemId.equals(topSystemId)) {
             resolvedSystemId = modelPublicId;
-        } else if (systemId.equals(topSystemId)) {
-            resolvedSystemId = null;
         } else if (reverseUrlMap.get(systemId) != null) {
             resolvedSystemId = reverseUrlMap.get(systemId);
         } else {
             LOG.debug("Unable to map systemId - " + systemId);
         }
-        
-        String key;
-        if (resolvedSystemId == null || "".equals(resolvedSystemId)) {
-            // No # here because PGML parser needs bare UUID/xmi.id
-            key = xmiId;            
-        } else {
-            key = resolvedSystemId + "#" + xmiId;                
-        }
 
-        if (!idToObjects.containsKey(key) 
-                && !objectsToId.containsKey(object.refMofId())) {
-            super.register(resolvedSystemId, xmiId, object);
-            idToObjects.put(key, object);
-            objectsToId.put(object.refMofId(),
-                    new XmiReference(resolvedSystemId, xmiId));
-        } else {
-            if (idToObjects.containsKey(key) 
-                    && idToObjects.get(key) != object) {
-                ((ModelElement) idToObjects.get(key)).getName();
-                LOG.error("Collision - multiple elements with same xmi.id : "
-                        + xmiId);
-                throw new IllegalStateException(
-                        "Multiple elements with same xmi.id");
-            }
-            if (objectsToId.containsKey(object.refMofId())) {
+        RefObject o = getReferenceInt(resolvedSystemId, xmiId);
+        if (o == null) {
+            if (mofidToXmiref.containsKey(object.refMofId())) {
+                XmiReference ref = mofidToXmiref.get(object.refMofId());
                 // For now just skip registering this and ignore the request, 
                 // but the real issue is that MagicDraw serializes the same 
                 // object in two different composition associations, first in
                 // the referencing file and second in the referenced file
                 LOG.debug("register called twice for the same object "
                         + "- ignoring second");
-                XmiReference ref = objectsToId.get(object.refMofId());
                 LOG.debug(" - first reference = " + ref.getSystemId() + "#"
                         + ref.getXmiId());
                 LOG.debug(" - 2nd reference   = " + systemId + "#" + xmiId);
+                LOG.debug(" -   resolved system id   = " + resolvedSystemId );
+            } else {
+                registerInt(resolvedSystemId, xmiId, object);
+                super.register(resolvedSystemId, xmiId, object);
+            }
+        } else {
+            if (o.equals(object)) {
+                // Object from a different file, register with superclass so it
+                // can resolve all references
+                super.register(resolvedSystemId, xmiId, object);            
+            } else {
+               LOG.error("Collision - multiple elements with same xmi.id : "
+                        + xmiId);
+                throw new IllegalStateException(
+                        "Multiple elements with same xmi.id");
+            }
+        }
+    }
+
+    private RefObject getReferenceInt(String docId, String xmiId)  {
+        Map<String, Object> map = idToObject.get(docId);
+        if (map != null) {
+            RefObject result = (RefObject) map.get(xmiId);
+            if (result == null && LOG.isDebugEnabled()) {
+                LOG.debug("No internal reference for - " + docId 
+                        + "#" + xmiId);
             }
+            return result;
+        }
+        return null;
+    }
+    
+    private void registerInt(String docId, String xmiId, RefObject object) {
+        Map<String, Object> map = idToObject.get(docId);
+        if (map == null) {
+            map = new HashMap<String, Object>();
+            idToObject.put(docId,map);
+        }
+        map.put(xmiId, object);
+        mofidToXmiref.put(object.refMofId(), new XmiReference(docId, xmiId));
+    }
+    
+    /*
+     * @see org.netbeans.lib.jmi.xmi.XmiContext#getReference(java.lang.String, 
java.lang.String)
+     */
+    public RefObject getReference (String docId, String xmiId) {
+        RefObject ro = getReferenceInt(docId, xmiId);
+        if (ro == null && !idToObject.containsKey(docId)) {
+            ro = super.getReference(docId, xmiId);
+        }
+        if (ro == null) {
+            // TODO: Distinguish between deferred resolution and things which
+            // are unresolved at end of load and should be reported to user.
+            LOG.error("Failed to resolve " + docId + "#" + xmiId );
         }
+        // TODO: Count/report unresolved references
+        return ro;
     }
 
     /**
-     * Return complete map of all registered objects.
+     * Return map of all registered objects for top level document.
      * 
      * @return map of xmi.id to RefObject correspondences
      */
-    public Map<String, Object> getIdToObjectMap() {
-        return idToObjects;
+    Map<String, Object> getIdToObjectMap() {
+        return getIdToObjectMaps().get(topSystemId);
     }
 
     /**
+     * @return map of maps from xmi ID to object
+     */
+    Map<String, Map<String, Object>> getIdToObjectMaps() {
+        return idToObject;
+    }
+    
+    /**
      * Reinitialize the object id maps to the empty state.
      */
-    public void clearIdMaps() {
-        idToObjects.clear();
-        objectsToId.clear();
+    void clearIdMaps() {
+        getIdToObjectMap().clear();
+        mofidToXmiref.clear();
+        topSystemId = null;
     }
     
     
@@ -276,7 +356,9 @@
     /////////////////////////////////////////////////////
 
     /**
-     * Convert a System ID from an HREF (typically filespec-like) to a URL.
+     * Convert a System ID from an HREF which may be relative or otherwise in
+     * need of resolution to an absolute URL.
+     * 
      * Copied from AndroMDA 3.1 by Ludo (rastaman)
      * see @link org.andromda.repositories.mdr.MDRXmiReferenceResolverContext
      * @see org.netbeans.lib.jmi.xmi.XmiContext#toURL(java.lang.String)
@@ -287,6 +369,9 @@
             LOG.debug("attempting to resolve Xmi Href --> '" + systemId + "'");
         }
 
+        // TODO: Using just the last piece of the ID leaves the potential for
+        // name collisions if two linked files have the same name in different
+        // directories
         final String suffix = getSuffix(systemId);
 
         // if the model URL has a suffix of '.zip' or '.jar', get
@@ -304,6 +389,7 @@
             }
             if (modelUrl == null) {
                 // If systemId is a valid URL, simply use it.
+                // TODO: This causes a network connection attempt for profiles
                 modelUrl = getValidURL(fixupURL(systemId));
             }
             if (modelUrl == null) {
@@ -328,13 +414,15 @@
             if (modelUrl != null) {
                 LOG.info("Referenced model --> '" + modelUrl + "'");
                 urlMap.put(suffixWithExt, modelUrl);
+                pendingProfiles.put(systemId, modelUrl);
                 String relativeUri = systemId;
                 try {
                     if (baseUri != null) {
-                        relativeUri = baseUri.relativize(new URI(systemId))
+                        relativeUri = baseUri.relativize(modelUrl.toURI())
                                 .toString();
                         if (LOG.isDebugEnabled()) {
-                            LOG.debug("       system ID " + systemId
+                            LOG.debug("       system ID " + systemId 
+                                    + " modelUrl " + modelUrl 
                                     + "\n  relativized as " + relativeUri);
                         }
                     } else {
@@ -410,6 +498,9 @@
         Collection<File> candidates = new ArrayList<File>();
         if (basePath != null && basePath.length() > 0) {
             Collection<File> dirs = new ArrayList<File>();
+            // TODO: This should be done (if desired/needed) by the calling
+            // code, not here.  It's not always the case that searching all
+            // subdirectories is desirable.
             dirs = findAllInternalDirectories(new File(basePath));
             for (File dir : dirs) {
                 candidates.add(new File(dir, fileName));
@@ -580,15 +671,31 @@
 
     @Override
     public void readExternalDocument(String arg0) {
-        try {
-            super.readExternalDocument(arg0);
-        } catch (DebugException e) {
-            // Unfortunately the MDR super implementation throws
-            // DebugException with just the message from the causing
-            // exception rather than nesting the exception itself, so
-            // we don't have all the information we'd like
-            LOG.error("Error reading external document " + arg0);
-            throw new XmiReferenceRuntimeException(arg0, e);
+        // We've got a profile read pending - handle it ourselves now
+        URL url = pendingProfiles.remove(arg0);
+        if (url != null) {
+            InputSource is = new InputSource(url.toExternalForm());
+            is.setPublicId(arg0);
+            XmiReaderImpl reader = new XmiReaderImpl(modelImpl);
+            try {
+                reader.parse(is, true);
+            } catch (UmlException e) {
+                LOG.error("Error reading referenced profile " + arg0);
+                throw new XmiReferenceRuntimeException(arg0, e);
+            }
+        } else if (!(public2SystemIds.containsKey(arg0))) {
+            // Otherwise if it's not something we've already read, just
+            // punt to the super class.
+            try {
+                super.readExternalDocument(arg0);
+            } catch (DebugException e) {
+                // Unfortunately the MDR super implementation throws
+                // DebugException with just the message from the causing
+                // exception rather than nesting the exception itself, so
+                // we don't have all the information we'd like
+                LOG.error("Error reading external document " + arg0);
+                throw new XmiReferenceRuntimeException(arg0, e);
+            }
         }
     }
 }

Modified: 
trunk/src/argouml-core-model-mdr/tests/org/argouml/model/mdr/AbstractMDRModelImplementationTestCase.java
Url: 
http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-core-model-mdr/tests/org/argouml/model/mdr/AbstractMDRModelImplementationTestCase.java?view=diff&pathrev=18269&r1=18268&r2=18269
==============================================================================
--- 
trunk/src/argouml-core-model-mdr/tests/org/argouml/model/mdr/AbstractMDRModelImplementationTestCase.java
    (original)
+++ 
trunk/src/argouml-core-model-mdr/tests/org/argouml/model/mdr/AbstractMDRModelImplementationTestCase.java
    2010-04-15 10:53:16-0700
@@ -82,8 +82,9 @@
     
     protected void setUp() throws Exception {
         super.setUp();
-        if (!initialized)
+        if (!initialized) {
             init();
+        }
     }
 
 }

------------------------------------------------------
http://argouml.tigris.org/ds/viewMessage.do?dsForumId=5905&dsMessageId=2584072

To unsubscribe from this discussion, e-mail: 
[[email protected]].

Reply via email to