Author: tfmorris
Date: 2007-08-09 12:42:59-0700
New Revision: 13280
Modified:
trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java
trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java
Log:
Extend XmiReader API to manage search path for resolving external references.
Enhance reference resolver to support cross file references, resource based profiles, and writing as well as reading
Modified: trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java?view=diff&rev=13280&p1=trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java&p2=trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java&r1=13279&r2=13280
==============================================================================
--- trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java (original)
+++ trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReaderImpl.java 2007-08-09 12:42:59-0700
@@ -34,6 +34,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import javax.jmi.reflect.InvalidObjectException;
@@ -109,7 +110,7 @@
*/
private int ignoredElementCount;
-
+ private static List<String> searchDirs = new ArrayList();
/**
* Constructor for XMIReader.
@@ -124,36 +125,30 @@
}
- public Collection parse(InputSource pIs) throws UmlException {
- return parse(pIs, false);
+ public Collection parse(InputSource inputSource) throws UmlException {
+ return parse(inputSource, false);
}
-
- public Collection parse(InputSource pIs, boolean profile)
+ public Collection parse(InputSource inputSource, boolean profile)
throws UmlException {
Collection<RefObject> newElements = Collections.EMPTY_LIST;
RefPackage extent = modelPackage;
try {
- LOG.info("Loading '" + pIs.getSystemId() + "'");
+ LOG.info("Loading '" + inputSource.getSystemId() + "'");
InputConfig config = new InputConfig();
config.setUnknownElementsListener(this);
config.setUnknownElementsIgnored(true);
resolver = new XmiReferenceResolverImpl(new RefPackage[] {extent},
- config, modelImpl.getObjectToId());
+ config, modelImpl.getObjectToId(), searchDirs, profile);
config.setReferenceResolver(resolver);
XMIReader xmiReader =
XMIReaderFactory.getDefault().createXMIReader(config);
- // Copy stream to a file to be sure it can be repositioned.
- // TODO: find a way to remove this, since this *always* alterate the
- // performances for reading an XMI file, even if it's not UML 1.4.
- File tmpFile = copySource(pIs);
-
/*
* MDR has a hardcoded printStackTrace on all exceptions,
* even if they're caught, which is unsightly, so we handle
@@ -189,9 +184,14 @@
+ numElements);
try {
+ String systemId = inputSource.getSystemId();
+// if (systemId == null) {
+// File file = copySource(inputSource);
+// systemId = file.toURL().toExternalForm();
+// }
newElements =
- xmiReader.read(tmpFile.toURI().toString(), extent);
-
+ xmiReader.read(inputSource.getByteStream(), systemId, extent);
+
// If a UML 1.3 file, attempt to upgrade it to UML 1.4
if (uml13) {
// First delete model data from our first attempt
@@ -201,8 +201,10 @@
resolver.clearIdMaps();
startTopElements = modelImpl.getFacade().getRootElements();
- newElements = convertAndLoadUml13(pIs.getSystemId(),
+ File tmpFile = copySource(inputSource);
+ newElements = convertAndLoadUml13(inputSource.getSystemId(),
extent, xmiReader, tmpFile);
+ tmpFile.delete();
}
numElements = modelImpl.getFacade().getRootElements().size()
@@ -421,7 +423,7 @@
tmpOutFile.deleteOnExit();
FileOutputStream out = new FileOutputStream(tmpOutFile);
InputStream in = input.getByteStream();
-
+
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
@@ -493,9 +495,7 @@
};
- /*
- * @see org.netbeans.lib.jmi.xmi.UnknownElementsListener#elementFound(java.lang.String)
- */
+
public void elementFound(String name) {
// Silently ignore anything specified by caller attempt to continue
if (ignoredElements != null) {
@@ -528,9 +528,6 @@
}
- /*
- * @see org.argouml.model.XmiReader#setIgnoredElements(java.lang.String[])
- */
public boolean setIgnoredElements(String[] elementNames) {
if (elementNames == null) {
elementNames = new String[] {};
@@ -540,17 +537,12 @@
return true;
}
- /*
- * @see org.argouml.model.XmiReader#getIgnoredElements()
- */
+
public String[] getIgnoredElements() {
return ignoredElements;
}
- /*
- * @see org.argouml.model.XmiReader#getIgnoredElementCount()
- */
public int getIgnoredElementCount() {
return ignoredElementCount;
}
@@ -559,4 +551,18 @@
public String getTagName() {
return "XMI";
}
+
+
+ public void addSearchPath(String path) {
+ searchDirs.add(path);
+ }
+
+ public void removeSearchPath(String path) {
+ searchDirs.remove(path);
+ }
+
+ public List<String> getSearchPath() {
+ return searchDirs;
+ }
+
}
Modified: trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java?view=diff&rev=13280&p1=trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java&p2=trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java&r1=13279&r2=13280
==============================================================================
--- trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java (original)
+++ trunk/src/model-mdr/src/org/argouml/model/mdr/XmiReferenceResolverImpl.java 2007-08-09 12:42:59-0700
@@ -75,6 +75,10 @@
private static final Logger LOG =
Logger.getLogger(XmiReferenceResolverImpl.class);
+ private static final String PROFILE_RESOURCE_PATH = "/org/argouml/model/mdr/profiles/";
+ private static final String PROFILE_BASE_URL = "http://argouml.org/profiles/uml14";
+ private static final String PROFILE_FILE = PROFILE_BASE_URL + "/" + "default-uml14.xmi";
+
private Map<String, Object> idToObjects =
Collections.synchronizedMap(new HashMap<String, Object>());
@@ -116,16 +120,19 @@
*/
private Map<String, String> reverseUrlMap = new HashMap<String, String>();
+ private boolean profile;
+
/**
* Constructor.
* @see org.netbeans.lib.jmi.xmi.XmiContext#XmiContext(javax.jmi.reflect.RefPackage[], org.netbeans.api.xmi.XMIInputConfig)
* (see also {link org.netbeans.api.xmi.XMIReferenceResolver})
*/
- XmiReferenceResolverImpl(RefPackage[] extents,
- XMIInputConfig config, Map<String, XmiReference> objectToIdMap) {
+ XmiReferenceResolverImpl(RefPackage[] extents, XMIInputConfig config,
+ Map<String, XmiReference> objectToIdMap, List<String> searchDirs, boolean isProfile) {
super(extents, config);
- registerSearchPath();
objectsToId = objectToIdMap;
+ modulesPath = searchDirs;
+ profile = isProfile;
}
/**
@@ -141,25 +148,34 @@
public void register(String systemId, String xmiId, RefObject object) {
if (LOG.isDebugEnabled()) {
LOG.debug("Registering XMI ID '" + xmiId
- + "' in system ID '" + systemId + "'");
+ + "' in system ID '" + systemId
+ + "' to object with MOF ID '" + object.refMofId() + "'");
}
- super.register(systemId, xmiId, object);
+
if (topSystemId == null) {
topSystemId = systemId;
try {
baseUri = new URI(
systemId.substring(0, systemId.lastIndexOf('/') + 1));
} catch (URISyntaxException e) {
- LOG.error("Bad URI syntax for base URI from XMI document", e);
+ LOG.warn("Bad URI syntax for base URI from XMI document " + systemId, e);
+ baseUri = null;
}
LOG.debug("Top system ID set to " + topSystemId);
}
- if (systemId == topSystemId) {
+ if (profile) {
+ // TODO: Support multiple named profiles here
+ //systemId = PROFILE_DIR + "/" + <profilename>;
+ systemId = PROFILE_FILE;
+ } else if (systemId == topSystemId) {
systemId = null;
- } else {
+ } else if (reverseUrlMap.get(systemId) != null) {
systemId = reverseUrlMap.get(systemId);
+ } else {
+ LOG.debug("Unable to map systemId - " + systemId);
}
+
String key;
if (systemId == null) {
// No # here because PGML parser needs bare UUID/xmi.id
@@ -168,15 +184,27 @@
key = systemId + "#" + xmiId;
}
- if (!idToObjects.containsKey(key)) {
+ if (!idToObjects.containsKey(key)
+ && !objectsToId.containsKey(object.refMofId())) {
+ super.register(systemId, xmiId, object);
idToObjects.put(key, object);
objectsToId.put(object.refMofId(),
new XmiReference(systemId, xmiId));
} else {
- if (idToObjects.get(key) != object) {
+ if (idToObjects.containsKey(key) && idToObjects.get(key) != object) {
LOG.error("Collision - multiple elements with same xmi.id : "
+ xmiId);
}
+ if (objectsToId.containsKey(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);
+ }
}
}
@@ -197,25 +225,6 @@
objectsToId.clear();
}
- /**
- * Set up module search path to be used by AndroMDA URL resolver.
- * The path is retrieved from shared state (a system property) which
- * is set up externally (currently by
- * org.argouml.uml.ProfileJava#loadProfile() which is probably
- * the wrong place for it)
- */
- private void registerSearchPath() {
- //TODO: Replace by something elegant (i.e in the Model, or anything
- //accessible by the components of ArgoUML base and this class).
- String pathList =
- System.getProperty("org.argouml.model.modules_search_path");
- if (pathList != null) {
- String[] paths = pathList.split(",");
- for (String path : paths) {
- addModuleSearchPath(path);
- }
- }
- }
/////////////////////////////////////////////////////
////////// Begin AndroMDA Code //////////////////////
@@ -298,16 +307,21 @@
urlMap.put(suffixWithExt, modelUrl);
String relativeUri = systemId;
try {
+ if (baseUri != null) {
relativeUri = baseUri.relativize(new URI(systemId))
.toString();
LOG.debug(" system ID " + systemId
+ "\n relativized as " + relativeUri);
+ } else {
+ relativeUri = systemId;
+ }
} catch (URISyntaxException e) {
LOG.error("Error relativizing system ID " + systemId, e);
+ relativeUri = systemId;
}
- // MDR will register the first form in the actual file that it
- // reads in and the second form when it resolves
- // an external reference
+ // TODO: Check whether this is really needed. I think it's
+ // left over from an incomplete understanding of the MagicDraw
+ // composition error problem - tfm
reverseUrlMap.put(modelUrl.toString(), relativeUri);
reverseUrlMap.put(systemId, relativeUri);
}
@@ -399,19 +413,37 @@
* @return the suffix as a String.
*/
private URL findModelUrlOnClasspath(String systemId) {
- String modelName = systemId.substring(systemId.lastIndexOf("/") + 1,
- systemId.length());
+ final String dot = ".";
+ String modelName = systemId;
+ if (systemId.startsWith(PROFILE_BASE_URL)) {
+ modelName = PROFILE_RESOURCE_PATH
+ + systemId.substring(PROFILE_BASE_URL.length() + 1);
+ // TODO: Look for profiles in user specified directory as well
+ } else {
+ int filenameIndex = systemId.lastIndexOf("/");
+ if (filenameIndex > 0) {
+ modelName = systemId.substring(filenameIndex + 1, systemId
+ .length());
+ } else {
+ LOG.warn("Received systemId with no '/'" + systemId);
+ }
- // TODO: The following will fail to find files with embedded dots such
- // as andromda-profile-datatype-3.1.xml - tfm
-
- String dot = ".";
- // remove the first prefix because it may be an archive
- // (like magicdraw)
- modelName = modelName.substring(0, modelName.lastIndexOf(dot));
+
+ // remove the first prefix because it may be an archive
+ // (like magicdraw)
+ if (modelName.lastIndexOf(dot) > 0) {
+ modelName = modelName.substring(0, modelName.lastIndexOf(dot));
+ }
+ }
URL modelUrl = Thread.currentThread().getContextClassLoader()
.getResource(modelName);
+ // TODO: Not sure whether the above is better in some cases, but
+ // the code below is better for both Java Web Start and Eclipse.
+ if (modelUrl == null) {
+ modelUrl = this.getClass().getResource(modelName);
+ }
+ // TODO: Is this adequate for finding profiles in Java WebStart jars? - tfm
if (modelUrl == null) {
if (CLASSPATH_MODEL_SUFFIXES != null
&& CLASSPATH_MODEL_SUFFIXES.length > 0) {
@@ -424,6 +456,10 @@
if (modelUrl != null) {
break;
}
+ modelUrl = this.getClass().getResource(modelName);
+ if (modelUrl != null) {
+ break;
+ }
}
}
}
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.