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]].
