svn commit: r18269 - trunk/src: argouml-app/tests/org/argouml/persistence argouml-core-model-mdr/src/org/argouml/model/mdr argouml-core-model-mdr/tests/org/argouml/model/mdr

[email protected]
Newsgroups gmane.comp.lang.uml.argouml.cvs
Message-ID <[email protected]>
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]].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.