Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » M2T (model-to-text transformation) » JET2 and access to UML model
JET2 and access to UML model [message #50553] Thu, 25 September 2008 02:48 Go to next message
Timothy Marc is currently offline Timothy Marc
Messages: 547
Registered: July 2009
Senior Member
Hi all,

i started yesterday my first approach with JET2, but i didn't get very far
:) I want to generate code from an UML2 model with JET2. Here are my
issues:

1. How to pass a model element, e.g. a class, to a template, invoked via
ws:file.
2. How to access the generated xmi::id-Attribute. Look:

<packagedElement xmi:type="uml:Class"
xmi:id="_o_PXAIoxEd2LZNhYPFI7ng" name="Criticer"/>

I had to access this id because for the handling of protected regions.
But when i try to access it with

Id: <c:get select=$eClassifier/@id/>.

no output will be produced.

Any help would be appreciated.

Timothy
Re: JET2 and access to UML model [message #50661 is a reply to message #50553] Thu, 25 September 2008 10:11 Go to previous messageGo to next message
Paul Elder is currently offline Paul Elder
Messages: 849
Registered: July 2009
Senior Member
Timothy:

I'll answer in two parts: 1) navigating UML documents with JETs XPath and 2)
passing variables to templates

---- Part 1 - Navigating UML/EMF documents with JET2 & XPath ---
The first important lesson is thatJET2 DOES NOT read the XMI serialization
of a UML model (or any other EMF-based model).

Instead, it uses EMF to load the on-disk document into memory. JET2 gets
handed an EMF Resource containing objects defined by the UML2 API. The JET2
XPath engine the uses EMF's reflective APIs to make navigate the document.
It interprets the EMF-provided metadata as follows:

1) EReference feature names (such as packedElement) are treated as Element
names.
2) EAttribute feature names (such as name) are treated as Attribute names.
3) the EMF Resource object is treated as a Document root, and is matched by
the XPath /
4) any object directly contained by a Resource is treated as an element
matched by the name 'contents' (mirroring Resource.getContents())
5) the EClass name of an object (eObject.eClass().getName()) is treated as
an Element name.

So, if you point JET at a UML2 model with the following containment
structure:

Model: myModel
Package: myPackage
Class: Criticer
Property: x of type Other
Class: Other
Package: otherPackage

You could write the following XPath expressions:

To match the Model object:
/contents (uses rules 3 to match the Resource & 4 to match the
contents)
/Model (uses rules 3 to match the Resource & 5 to match an object of
eClass Model)

To match the Package myPackage, assuming the $model refers to a Model
object:

$model/Package[@name='myPackage']
$model/packagedElements[self::Package and @name='MyPackage']

The self::Package test uses the 'self' axis coupled with rule 5 to test the
type of an object. This is the closet you can come reading the xmi:type
attribute you see persisted in the XMI.

Assuming $property refers to a Class object, you could get its type as
follows:

$property/type/@name

Here, the step 'type' follows the EReference feature 'type', even though it
is not a containment relation. Also not that since the type EReference
feature by be null, the expression my return no value.

---- Part 2: Using JET variables and passing data to templates ---

Second lesson of JET. All variables are global, although some tags that
create variables will destroy variables they have created, and restore
previous variable values when the tag handler completes.

So, a simple-minded main.jet that invokes a template on UML Class objects
found in packages contained directly in the root Model object would look
something like:

<%-- setVariable defines and sets a global variable 'model' --%>
<c:setVariable var="model" select="/Model"/>

<%-- iterate defines a variable 'package' which is destroyed or restored at
the end of the loop --%>
<c:iterate select="$model/Package" var="package">

<%-- iterate defines a variable 'class' which is destroyed or restored
at the end of the loop --%>
<c:iterate select='$package/Class" var="class">
<%-- the template buildMeAClass can use the following variables:
model, package, class --%>
<ws:file path="..." template="templates/buildMeAClass.java.jet"/>
</c:iterate>
</c:iterate>

If you want to get more interesting and find all Class objects in all
Packages, you could use XPaths // step to do something like:

<c:iterate select="$model//Class" var="Class">
<%-- the template buildMeAClass can use the following variables:
model, class --%>
<ws:file path="..." template="templates/buildMeAClass.java.jet"/>
</c:iterate>

But, this will end up finding more Classes than you might want. For example,
it will find classes nested within classes. A predicate could limit this to
classes directly contained in a Package: $model//Class[parent::Package]. But
this would still find Packages which are contained in something other than
Packages. For example, Components can contain Packages, perhaps an
undesireable outcome.

IMHO, if you want complete control you have write a bit recursive code:

------ main.jet ---------
<%-- setVariable defines and sets a global variable 'model' --%>
<c:setVariable var="model" select="/Model"/>

<%-- Initialize package to $model, the included template below works with
$package --%>
<c:setVariable var="package" select="$model"/>

<%-- the passVariables attribute saves away all current variable values, and
then sets model & package to their --%>
<%-- current values. On returning, all variables, including model & package
are restored to the saved values --%>
<c:include template="templates/doPackageClasses.jet"
passVariables="model,package"/>
------ End: main.jet ---------

Here are the contents of doPackageClasses.jet:

----- doPackageClasses.jet -----
<%-- first, invoke the template on each class in $package --%>
<c:iterate select="$package/Class" var="class">
<%-- the template buildMeAClass can use the following variables: model,
package, class --%>
<ws:file path="..." template="templates/buildMeAClass.java.jet"/>
</c:iterate>

<%-- now recurse over contained packages --%>
<%-- c:iterate saves the value of $package and then sets it to the
appropriate subpackage during each interation --%>
<c:iterate select="$package/Package" var="package">
<c:include template="templates/doPackageClasses.jet"
passVariables="model,package"/>
<%-- regardless of what happen in the include, here $package would refer
to --%>
<%-- the Package handled by the current loop iteration --%>
</c:iterate>
<%-- regardless of what happen in the include or iterate, here $package
would refer to --%>
<%-- the Package 'passed' to the template --%>
----- End: doPackageClasses.jet -----

Hope this helps,

Paul
Re: JET2 and access to UML model [message #50745 is a reply to message #50661] Thu, 25 September 2008 14:04 Go to previous messageGo to next message
Timothy Marc is currently offline Timothy Marc
Messages: 547
Registered: July 2009
Senior Member
Paul,

what a great answer. Thank you very much, this is much better than anything
i found in the web. I'm really grateful.
But one last question: I want to realize traceability between the
retransformation of a model. I know, that JMerge provides this capability,
but i want to made a merging mechanism on my own. Therefore, i need access
to the xmi:id attribute in the XMI serialization stream.

I tried something like this:

<c:get select=$class/@id ... />

but that doesn't produce any result. But, i need access to this
identification attributes, which are generated by the UML tool (MagicDraw or
Papyrus/Topcased).

Thanks again, Timothy


"Paul Elder" <pelder@ca.ibm.com> schrieb im Newsbeitrag
news:gbg66h$vdn$1@build.eclipse.org...
> Timothy:
>
> I'll answer in two parts: 1) navigating UML documents with JETs XPath and
> 2) passing variables to templates
>
> ---- Part 1 - Navigating UML/EMF documents with JET2 & XPath ---
> The first important lesson is thatJET2 DOES NOT read the XMI serialization
> of a UML model (or any other EMF-based model).
>
> Instead, it uses EMF to load the on-disk document into memory. JET2 gets
> handed an EMF Resource containing objects defined by the UML2 API. The
> JET2 XPath engine the uses EMF's reflective APIs to make navigate the
> document. It interprets the EMF-provided metadata as follows:
>
> 1) EReference feature names (such as packedElement) are treated as Element
> names.
> 2) EAttribute feature names (such as name) are treated as Attribute names.
> 3) the EMF Resource object is treated as a Document root, and is matched
> by the XPath /
> 4) any object directly contained by a Resource is treated as an element
> matched by the name 'contents' (mirroring Resource.getContents())
> 5) the EClass name of an object (eObject.eClass().getName()) is treated as
> an Element name.
>
> So, if you point JET at a UML2 model with the following containment
> structure:
>
> Model: myModel
> Package: myPackage
> Class: Criticer
> Property: x of type Other
> Class: Other
> Package: otherPackage
>
> You could write the following XPath expressions:
>
> To match the Model object:
> /contents (uses rules 3 to match the Resource & 4 to match the
> contents)
> /Model (uses rules 3 to match the Resource & 5 to match an object of
> eClass Model)
>
> To match the Package myPackage, assuming the $model refers to a Model
> object:
>
> $model/Package[@name='myPackage']
> $model/packagedElements[self::Package and @name='MyPackage']
>
> The self::Package test uses the 'self' axis coupled with rule 5 to test
> the type of an object. This is the closet you can come reading the
> xmi:type attribute you see persisted in the XMI.
>
> Assuming $property refers to a Class object, you could get its type as
> follows:
>
> $property/type/@name
>
> Here, the step 'type' follows the EReference feature 'type', even though
> it is not a containment relation. Also not that since the type EReference
> feature by be null, the expression my return no value.
>
> ---- Part 2: Using JET variables and passing data to templates ---
>
> Second lesson of JET. All variables are global, although some tags that
> create variables will destroy variables they have created, and restore
> previous variable values when the tag handler completes.
>
> So, a simple-minded main.jet that invokes a template on UML Class objects
> found in packages contained directly in the root Model object would look
> something like:
>
> <%-- setVariable defines and sets a global variable 'model' --%>
> <c:setVariable var="model" select="/Model"/>
>
> <%-- iterate defines a variable 'package' which is destroyed or restored
> at the end of the loop --%>
> <c:iterate select="$model/Package" var="package">
>
> <%-- iterate defines a variable 'class' which is destroyed or restored
> at the end of the loop --%>
> <c:iterate select='$package/Class" var="class">
> <%-- the template buildMeAClass can use the following variables:
> model, package, class --%>
> <ws:file path="..." template="templates/buildMeAClass.java.jet"/>
> </c:iterate>
> </c:iterate>
>
> If you want to get more interesting and find all Class objects in all
> Packages, you could use XPaths // step to do something like:
>
> <c:iterate select="$model//Class" var="Class">
> <%-- the template buildMeAClass can use the following variables:
> model, class --%>
> <ws:file path="..." template="templates/buildMeAClass.java.jet"/>
> </c:iterate>
>
> But, this will end up finding more Classes than you might want. For
> example, it will find classes nested within classes. A predicate could
> limit this to classes directly contained in a Package:
> $model//Class[parent::Package]. But this would still find Packages which
> are contained in something other than Packages. For example, Components
> can contain Packages, perhaps an undesireable outcome.
>
> IMHO, if you want complete control you have write a bit recursive code:
>
> ------ main.jet ---------
> <%-- setVariable defines and sets a global variable 'model' --%>
> <c:setVariable var="model" select="/Model"/>
>
> <%-- Initialize package to $model, the included template below works with
> $package --%>
> <c:setVariable var="package" select="$model"/>
>
> <%-- the passVariables attribute saves away all current variable values,
> and then sets model & package to their --%>
> <%-- current values. On returning, all variables, including model &
> package are restored to the saved values --%>
> <c:include template="templates/doPackageClasses.jet"
> passVariables="model,package"/>
> ------ End: main.jet ---------
>
> Here are the contents of doPackageClasses.jet:
>
> ----- doPackageClasses.jet -----
> <%-- first, invoke the template on each class in $package --%>
> <c:iterate select="$package/Class" var="class">
> <%-- the template buildMeAClass can use the following variables: model,
> package, class --%>
> <ws:file path="..." template="templates/buildMeAClass.java.jet"/>
> </c:iterate>
>
> <%-- now recurse over contained packages --%>
> <%-- c:iterate saves the value of $package and then sets it to the
> appropriate subpackage during each interation --%>
> <c:iterate select="$package/Package" var="package">
> <c:include template="templates/doPackageClasses.jet"
> passVariables="model,package"/>
> <%-- regardless of what happen in the include, here $package would
> refer to --%>
> <%-- the Package handled by the current loop iteration --%>
> </c:iterate>
> <%-- regardless of what happen in the include or iterate, here $package
> would refer to --%>
> <%-- the Package 'passed' to the template --%>
> ----- End: doPackageClasses.jet -----
>
> Hope this helps,
>
> Paul
>
Re: JET2 and access to UML model [message #50768 is a reply to message #50745] Thu, 25 September 2008 15:35 Go to previous messageGo to next message
Paul Elder is currently offline Paul Elder
Messages: 849
Registered: July 2009
Senior Member
Timothy:

Unfortunately, the XMI ID is not available via the EMF reflective API. It
is, however, available from the ECoreUtil.getID(EObject). So, a little Java
code will have to be written.

My preference would be to do it in a custom XPath function, which is
declared via the org.eclipse.jet.xpathFunctions extension point.

The function implementation is a Java class that implements the interface
org.eclipse.jet.xpath.XPathFunction, and provides an implementation for the
evaluate method.

The method receives a List, one for each declared argument (the function
needs one). Unfortunately, the arguments types are a little mysterious - you
are looking for an EObject, but it will be packed into something called a
NodeSet, which is a specializaiton of java.util.Collection. Here's how I'd
do it:

import java.util.Collection;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jet.xpath.XPathFunction;
import org.eclipse.jet.xpath.XPathRuntimeException;

public class IdFunction implements XPathFunction {

@Override
public Object evaluate(List args) {
Object candidate = args.get(0);

if(candidate instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) candidate;
if(collection.size() > 0) {
candidate = collection.iterator().next();
}
}
if(candidate instanceof EObject) {
return EcoreUtil.getID((EObject)candidate);
}
throw new XPathRuntimeException("Argument to getId is not an
EObject");
}

}
Re: JET2 and access to UML model [message #50880 is a reply to message #50768] Sat, 27 September 2008 13:10 Go to previous messageGo to next message
Timothy Marc is currently offline Timothy Marc
Messages: 547
Registered: July 2009
Senior Member
Hey Paul,

thanks again, i've tried to implement it as a XPath extension. Therefore, I
declared an Extension in the plugin, that contains the transformation. I've
specified all the things, the Extension Point needs to know, but when i run
the transformation, an error is mentioned, because the getID() function was
not found.

The plugin.xml looks like this:

<extension
point="org.eclipse.jet.xpathFunctions">
<function implementation="de.wendland.tfh.se.jet.dpr.xpath.XMIIDFunction "
maxArgs="1"
minArgs="1"
name="getID">
</function>
</extension>

In the main.jet i use the following construct to get the id:

<c:get select="getID($eClassifier)"/>

but that doesn't work, however.

Do you know, what I'm doing wrong??

Thx
Timothy


"Paul Elder" <pelder@ca.ibm.com> schrieb im Newsbeitrag
news:gbgp5s$880$1@build.eclipse.org...
> Timothy:
>
> Unfortunately, the XMI ID is not available via the EMF reflective API. It
> is, however, available from the ECoreUtil.getID(EObject). So, a little
> Java code will have to be written.
>
> My preference would be to do it in a custom XPath function, which is
> declared via the org.eclipse.jet.xpathFunctions extension point.
>
> The function implementation is a Java class that implements the interface
> org.eclipse.jet.xpath.XPathFunction, and provides an implementation for
> the evaluate method.
>
> The method receives a List, one for each declared argument (the function
> needs one). Unfortunately, the arguments types are a little mysterious -
> you are looking for an EObject, but it will be packed into something
> called a NodeSet, which is a specializaiton of java.util.Collection.
> Here's how I'd do it:
>
> import java.util.Collection;
> import java.util.List;
>
> import org.eclipse.emf.ecore.EObject;
> import org.eclipse.emf.ecore.util.EcoreUtil;
> import org.eclipse.jet.xpath.XPathFunction;
> import org.eclipse.jet.xpath.XPathRuntimeException;
>
> public class IdFunction implements XPathFunction {
>
> @Override
> public Object evaluate(List args) {
> Object candidate = args.get(0);
>
> if(candidate instanceof Collection<?>) {
> Collection<?> collection = (Collection<?>) candidate;
> if(collection.size() > 0) {
> candidate = collection.iterator().next();
> }
> }
> if(candidate instanceof EObject) {
> return EcoreUtil.getID((EObject)candidate);
> }
> throw new XPathRuntimeException("Argument to getId is not an
> EObject");
> }
>
> }
>
>
Re: JET2 and access to UML model [message #50935 is a reply to message #50880] Mon, 29 September 2008 09:02 Go to previous messageGo to next message
Timothy Marc is currently offline Timothy Marc
Messages: 547
Registered: July 2009
Senior Member
However, at least, i get the extended XPath function work.
The tagLibrary doesn't work at all.

Timothy
"Timothy Marc" <timothymarc@freenet.de> schrieb im Newsbeitrag
news:gblp9f$hts$1@build.eclipse.org...
> Hey Paul,
>
> thanks again, i've tried to implement it as a XPath extension. Therefore,
> I declared an Extension in the plugin, that contains the transformation.
> I've specified all the things, the Extension Point needs to know, but when
> i run the transformation, an error is mentioned, because the getID()
> function was not found.
>
> The plugin.xml looks like this:
>
> <extension
> point="org.eclipse.jet.xpathFunctions">
> <function implementation="de.wendland.tfh.se.jet.dpr.xpath.XMIIDFunction "
> maxArgs="1"
> minArgs="1"
> name="getID">
> </function>
> </extension>
>
> In the main.jet i use the following construct to get the id:
>
> <c:get select="getID($eClassifier)"/>
>
> but that doesn't work, however.
>
> Do you know, what I'm doing wrong??
>
> Thx
> Timothy
>
>
> "Paul Elder" <pelder@ca.ibm.com> schrieb im Newsbeitrag
> news:gbgp5s$880$1@build.eclipse.org...
>> Timothy:
>>
>> Unfortunately, the XMI ID is not available via the EMF reflective API. It
>> is, however, available from the ECoreUtil.getID(EObject). So, a little
>> Java code will have to be written.
>>
>> My preference would be to do it in a custom XPath function, which is
>> declared via the org.eclipse.jet.xpathFunctions extension point.
>>
>> The function implementation is a Java class that implements the interface
>> org.eclipse.jet.xpath.XPathFunction, and provides an implementation for
>> the evaluate method.
>>
>> The method receives a List, one for each declared argument (the function
>> needs one). Unfortunately, the arguments types are a little mysterious -
>> you are looking for an EObject, but it will be packed into something
>> called a NodeSet, which is a specializaiton of java.util.Collection.
>> Here's how I'd do it:
>>
>> import java.util.Collection;
>> import java.util.List;
>>
>> import org.eclipse.emf.ecore.EObject;
>> import org.eclipse.emf.ecore.util.EcoreUtil;
>> import org.eclipse.jet.xpath.XPathFunction;
>> import org.eclipse.jet.xpath.XPathRuntimeException;
>>
>> public class IdFunction implements XPathFunction {
>>
>> @Override
>> public Object evaluate(List args) {
>> Object candidate = args.get(0);
>>
>> if(candidate instanceof Collection<?>) {
>> Collection<?> collection = (Collection<?>) candidate;
>> if(collection.size() > 0) {
>> candidate = collection.iterator().next();
>> }
>> }
>> if(candidate instanceof EObject) {
>> return EcoreUtil.getID((EObject)candidate);
>> }
>> throw new XPathRuntimeException("Argument to getId is not an
>> EObject");
>> }
>>
>> }
>>
>>
>
>
Re: JET2 and access to UML model [message #50963 is a reply to message #50880] Mon, 29 September 2008 11:53 Go to previous messageGo to next message
Paul Elder is currently offline Paul Elder
Messages: 849
Registered: July 2009
Senior Member
Timothy:

A couple of things.

1) JET 0.9.0 fails to find JET functions declared in a JET project. You can
do one of several things.
a) upgrated to the recently released JET 0.9.1
b) Define the function in a separate plug-in, and install that plug-in in
your Eclipse instance.
c) Launch a 'runtime workbench', and test your JET plug-in from there.

2) There is a bug in the getID function I sent you. I should know better
than to send code without testing it first. Turns out that EcoreUtil.getID()
only works if the underlying EClass declares one of its attributes as an ID.
And, it turns out the UML2 doesn't have any such attributes. They way that
those IDs are being applied to objects if via XMLResource.setID. Here is
updated code (that has been tested :-).

public Object evaluate(List args) {
Object candidate = args.get(0);

if(candidate instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) candidate;
if(collection.size() > 0) {
candidate = collection.iterator().next();
}
}
if(candidate instanceof EObject) {
final EObject eObject = (EObject)candidate;
final Resource resource = eObject.eResource();
final String id;
if(resource != null) {
// if the object is in a resource, get the URI fragment,
which uses
// EcoreUtil.getID() if found, but then falls back to
resource-specific
// ID mechanisms
id = resource.getURIFragment(eObject);
} else {
// Without a resource, we can only resort to...
id = EcoreUtil.getID(eObject);
}
if(id == null){
throw new XPathRuntimeException("No ECore ID found for " +
candidate);
}
return id;
}
throw new XPathRuntimeException("Argument is not an EObject");
}

Rather than add dependencies on XMLResource (which is in another plug-in), I
have used the more generic Resource.getFragmentURI() which first tries for a
directly declared object ID, and then falls back on resource specific ID
mechanisms such as is used by UML2.
Re: JET2 and access to UML model [message #51100 is a reply to message #50661] Tue, 30 September 2008 06:52 Go to previous messageGo to next message
Jochen Wuttke is currently offline Jochen Wuttke
Messages: 41
Registered: July 2009
Member
Hi Paul,

I'm having problems similar to Timothy's. My UML model uses profiles and
loading the model with the default EMF loader does not give me access to
the profile information in the .uml file. So I tried to use the generic
XML loader in the hope that it would blindly build something similar to
a DOM and let me access whatever I want. However, that way I can't
access simple attributes anymore.

Example:

When loading the UML with the default loader, the XPath expression
<c:setVariable select="Package/@name" var="packageName" />
correctly sets the variable.

When using the same expression with the EMFXML loader I get a null
pointer exception. Changing the expression to
<c:setVariable select="/XMI/Package/@name" var="packageName" />
get's rid of the null pointer exception, but the variable does not get set.
From your previous explanations I was getting the impression that the
loaders ignore or hide some of the information that is stored in
XMI/XML. Is that the problem, or am I missing something crucial here?

Jochen
Re: JET2 and access to UML model [message #51128 is a reply to message #51100] Tue, 30 September 2008 10:24 Go to previous messageGo to next message
Paul Elder is currently offline Paul Elder
Messages: 849
Registered: July 2009
Senior Member
Jochen:

Personally, I won't recommend reading the XMI (i.e. using the XML loader)
for UML models. My main problem with the XMI encoding of the model is that
it omits all attributes whose value equals the defaults. So, if you need any
of those values, your transformation must know what the defaults are. And,
if reading the XMI directly, you would be responsible for resolving
references from object-to-object. This may not be insurmountable, but it is
a pain.

Anyhow, let's look at the two possibility: 1) getting your XPath expressions
to work with the XML loader, and 2) getting profile information using the
EMF loader...

1) The problem with the XML loader is that the XPath engine doesn't let you
define namespaces... Here is an typical XMI snippet of a UML model.

<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.1" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ZYXBeansProfile="http:///schemas/ZYXBeansProfile/_2eYucI7sEd2s0PuARynQZw/2"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML"
xsi:schemaLocation="http:///schemas/ZYXBeansProfile/_2eYucI7sEd2s0PuARynQZw/2
ZYXBeansProfile.profile.uml#_Cs_bqY7tEd2s0PuARynQZw">
<uml:Model xmi:id="_Cs2PbI7tEd2s0PuARynQZw" name="my uml model">
<packageImport xmi:id="_Cs2PbY7tEd2s0PuARynQZw">
<importedPackage xmi:type="uml:Model"
href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
</packageImport>
<packagedElement xmi:type="uml:Class" xmi:id="_Cs2Pbo7tEd2s0PuARynQZw"
name="MyStereotypedClass"/>
<profileApplication xmi:id="_Cs2Pb47tEd2s0PuARynQZw">
<eAnnotations xmi:id="_Cs2PcI7tEd2s0PuARynQZw"
source="http://www.eclipse.org/uml2/2.0.0/UML">
<references xmi:type="ecore:EPackage"
href=" pathmap://UML_PROFILES/Standard.profile.uml#_yzU58YinEdqtvbn fB2L_5w"/>
</eAnnotations>
<appliedProfile
href="pathmap://UML_PROFILES/Standard.profile.uml#_0"/>
</profileApplication>
<profileApplication xmi:id="_Cs2PcY7tEd2s0PuARynQZw">
<eAnnotations xmi:id="_Cs2Pco7tEd2s0PuARynQZw"
source="http://www.eclipse.org/uml2/2.0.0/UML">
<references xmi:type="ecore:EPackage"
href="Default.profile.uml#_Cs_cO47tEd2s0PuARynQZw"/>
</eAnnotations>
<appliedProfile href="Default.profile.uml#_Cs_cOY7tEd2s0PuARynQZw"/>
</profileApplication>
<profileApplication xmi:id="_Cs2Pc47tEd2s0PuARynQZw">
<eAnnotations xmi:id="_Cs2PdI7tEd2s0PuARynQZw"
source="http://www.eclipse.org/uml2/2.0.0/UML">
<references xmi:type="ecore:EPackage"
href="Deployment.profile.uml#_Cs_ZkY7tEd2s0PuARynQZw"/>
</eAnnotations>
<appliedProfile
href="Deployment.profile.uml#_Cs_Zj47tEd2s0PuARynQZw"/>
</profileApplication>
<profileApplication xmi:id="_Cs2PdY7tEd2s0PuARynQZw">
<eAnnotations xmi:id="_Cs2Pdo7tEd2s0PuARynQZw"
source="http://www.eclipse.org/uml2/2.0.0/UML">
<references xmi:type="ecore:EPackage"
href="ZYXBeansProfile.profile.uml#_Cs_bqY7tEd2s0PuARynQZw"/ >
</eAnnotations>
<appliedProfile
href="ZYXBeansProfile.profile.uml#_Cs_bp47tEd2s0PuARynQZw"/ >
</profileApplication>
</uml:Model>
<ZYXBeansProfile:MyStereotype xmi:id="_Cs2Pd47tEd2s0PuARynQZw"
base_Class="_Cs2Pbo7tEd2s0PuARynQZw" myAttr="myAttrValue"/>
</xmi:XMI>

To match the model element, you really need to be able to write an
expression like this: /xmi:XMI/uml:Model/@name. But, the XPath engine
complains that the prefixes xmi and uml are not defined. This more verbose
expression would work:

/*[local-name() = 'XMI']/*[local-name() = 'Model']/@name

I have just committed changes to both the R0_9_maintenance stream and HEAD
that relax the XPath engine's checking so that

/XMI/Model/@name

would work, too.

2) Getting stereotype information when using the EMF/EMFXML model loaders.
When the UML model is loaded via EMF, the XPath engine is using EMF's
reflective APIs to interpet the model. However, like the xmi:id, the
stereotype applications accessors were not defined via EMF. But, like the
xmi:id, this can be overcome by creating an XPath function.

In this case, the function would probably take two arguments:

getStereotype(object, st-name)

It would could make use of two functions in the UML2 Element class:

getApplicableStereotype -
http://help.eclipse.org/ganymede/topic/org.eclipse.uml2.doc/ references/javadoc/org/eclipse/uml2/uml/Element.html#getAppl icableStereotype
(java.lang.String)
getStereotypeApplication -
http://help.eclipse.org/ganymede/topic/org.eclipse.uml2.doc/ references/javadoc/org/eclipse/uml2/uml/Element.html#getSter eotypeApplication(org.eclipse.uml2.uml.Stereotype)

Here's the code:

package ....;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.eclipse.jet.xpath.XPathFunction;
import org.eclipse.jet.xpath.XPathRuntimeException;
import org.eclipse.jet.xpath.XPathUtil;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Stereotype;

public class StereotypeFunction implements XPathFunction {

@Override
public Object evaluate(List args) {
Object candidate = args.get(0);
final String qualifiedName = XPathUtil.xpathString(args.get(1));

if(candidate instanceof Collection<?>) {
Collection<?> collection = (Collection<?>) candidate;
if(collection.size() > 0) {
candidate = collection.iterator().next();
}
}
if(candidate instanceof Element) {
final Element element = (Element) candidate;
final Stereotype appliedStereotype =
element.getAppliedStereotype(qualifiedName);
if(appliedStereotype != null) {
return
Collections.singletonList(element.getStereotypeApplication(a ppliedStereotype));
} else {
return Collections.EMPTY_LIST;
}
}
throw new XPathRuntimeException("Argument is not a UML Element");
}

}

You'd use it as follows:

stereotype($someObj, 'SomeProfile::SomeStereotype' )

It returns a collection, you it can be used in conditionals:

<c:if test=" stereotype(...) "> ... </c:if>

And, if the stereotype has properties/attributes, then they are accessible
via attribute steps:

<c:get select=" stereotype(...)/@myAttr "/>

I am hoping to get such functionality added to JET in the coming release,
either as a function (like above), or integerated more directly into the
XPath engine (imagine: $myObj/MyProfile:MyStereotype/@myAttr )

Paul

"Jochen" <jochen.wuttke@gmx.de> wrote in message
news:gbt0ck$8e7$1@build.eclipse.org...
> Hi Paul,
>
> I'm having problems similar to Timothy's. My UML model uses profiles and
> loading the model with the default EMF loader does not give me access to
> the profile information in the .uml file. So I tried to use the generic
> XML loader in the hope that it would blindly build something similar to a
> DOM and let me access whatever I want. However, that way I can't access
> simple attributes anymore.
>
> Example:
>
> When loading the UML with the default loader, the XPath expression
> <c:setVariable select="Package/@name" var="packageName" />
> correctly sets the variable.
>
> When using the same expression with the EMFXML loader I get a null pointer
> exception. Changing the expression to
> <c:setVariable select="/XMI/Package/@name" var="packageName" />
> get's rid of the null pointer exception, but the variable does not get
> set.
> From your previous explanations I was getting the impression that the
> loaders ignore or hide some of the information that is stored in XMI/XML.
> Is that the problem, or am I missing something crucial here?
>
> Jochen
Re: JET2 and access to UML model [message #51261 is a reply to message #51128] Tue, 30 September 2008 18:02 Go to previous messageGo to next message
Timothy Marc is currently offline Timothy Marc
Messages: 547
Registered: July 2009
Senior Member
Dear Paul,

thanks again for your good ideas. I think JET2 is very powerful, yet
extendeable, generic template engine. A great project. Thanks at all.

Timothy
Re: JET2 and access to UML model [message #51534 is a reply to message #51128] Thu, 02 October 2008 08:51 Go to previous messageGo to next message
Jochen Wuttke is currently offline Jochen Wuttke
Messages: 41
Registered: July 2009
Member
Hi Paul,

thanks for your reply.
After a lot of messing around I finally got the 0.9.2 milestone working
and the XPath stuff on "plain" XMI works. I'll still be using your
suggestion for XPath functions to implement the "advanced" functionality
of my transformation.

Jochen
Re: JET2 and access to UML model [message #53304 is a reply to message #51128] Fri, 21 November 2008 15:31 Go to previous message
Paul Elder is currently offline Paul Elder
Messages: 849
Registered: July 2009
Senior Member
All:

After some real world use, I have found the previous version of this
function to be seriously lacking. Here is one that works better:

package my.jet.functions;

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.jet.xpath.XPathFunction;
import org.eclipse.jet.xpath.XPathUtil;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Stereotype;

public class StereotypeFunction implements XPathFunction {

@SuppressWarnings("unchecked")
@Override
public Object evaluate(List args) {
Object candidate = args.get(0);
final String qualifiedName = XPathUtil.xpathString(args.get(1));

if(candidate instanceof Collection) {
Collection collection = (Collection) candidate;
if(collection.size() > 0) {
candidate = collection.iterator().next();
}
}
if(candidate instanceof Element) {
final Element element = (Element) candidate;
final Stereotype appliedStereotype =
element.getAppliedStereotype(qualifiedName);
EObject stereotypeApplication = appliedStereotype != null ?
element.getStereotypeApplication(appliedStereotype)
: null;
if(stereotypeApplication != null) {
return Collections.singletonList(stereotypeApplication);
} else {
return Collections.EMPTY_LIST;
}
}
return Collections.EMPTY_LIST;
}

}
Previous Topic:Resolving "non-containment" EReference's
Next Topic:Possible XPath/transformation bug when dealing with optional attributes
Goto Forum:
  


Current Time: Mon Jul 28 12:46:37 EDT 2014

Powered by FUDForum. Page generated in 0.02479 seconds