Home » Modeling » ATL » EMFTVM avoiding using elements from the output model
EMFTVM avoiding using elements from the output model [message #1114903] |
Mon, 23 September 2013 07:38  |
Eclipse User |
|
|
|
Hi everyone,
I'm trying to change my normal ATL transformation to use EMFTVM but I'm running into some problems.
Right now I'm getting this exception:
org.eclipse.m2m.atl.emftvm.util.VMException: java.lang.IllegalArgumentException: Cannot read properties of org.dews_online.ccui.core.view.viewparts.PhenomenonTreeView.viewerContribution:profile!Class, as it is contained in an output model
The code I'm using is:
helper def: xmlElements: Sequence(XML!Element) = XML!Element.allInstancesFrom('Plugin');
rule Model {
from
s: UML2!Model in IN (
not s.oclIsUndefined() and not (s.name = 'root model') and not (s.name =
'externals') and not (s.name = 'source references')
)
to
[...],
vac: UML2!Package (
name <- 'viewActions',
packagedElement <- thisModule.xmlElements -> select(e | e.name =
'viewContribution') -> collect(e | [color=red]thisModule.ActionSetClass(e)[/color])
)
}
lazy rule ActionSetClass {
from
s: XML!Element
to
r: UML2!Class (
name <- s.children -> select(e | e.oclIsTypeOf(XML!Attribute) and not e.
oclIsUndefined() and e.name = 'id').first().value
)
--- The stereotype can't be applied since the element is generated outside
--- the model.
do {
thisModule.wbactions <-thisModule.wbactions.union([color=red]r.setGroup()[/color]);
}
}
helper context UML2!Class def: setGroup(): Sequence(UML2!Class) =
if (thisModule.classes -> select(e | e.value.toUpper().
endsWith(self.name.toUpper() )).
notEmpty()) then
if (thisModule.classes -> select(e | e.value.toUpper().endsWith(self.name.
toUpper())).first().parent.name = 'actionSet')
then
Sequence{self}
else
Sequence{}
endif
else
Sequence{}
endif;
That's all the problematic code right now. So I understand that I shouldn't be targeting the output model elements, but how do I do this then?what's the proper way of using elements that have been transformed?
I've tried several thins but I don't really understand how should I address these elements to avoid this kind of exception, I'm really lost with EMFTVM but I'm just starting, so any help is welcome.
Thanks in advance,
regards,
Javier
|
|
| | | |
Re: EMFTVM avoiding using elements from the output model [message #1115612 is a reply to message #1115574] |
Tue, 24 September 2013 06:27   |
Eclipse User |
|
|
|
Thanks a lot Dennis! that was it, plus a condition I had added before on the lazy rule (in normal ATL those conditions don't get evaluated so that confused me too...)
Ok so my transformation works almost perfectly now in EMFTVM, but now comes the tricky part, I need to set values to the stereotyped classes, I can do this if the values are strings and such, but certain values are other stereotyped classes which are stereotyped in this very same transformation (meaning they had no stereotypes in the input model), to do this in normal ATL I used an endpoint rule and used the Output model, but I can't do that here (and shouldn't do that in normal ATL), so what would you recommend to do then?
Because I can't write it in the normal do section as some classes might not have yet been stereotyped, so then the values wouldn't be set properly.
Thanks a lot for your help Dennis!
regards,
Javier
|
|
| |
Re: EMFTVM avoiding using elements from the output model [message #1118182 is a reply to message #1117402] |
Fri, 27 September 2013 02:28   |
Eclipse User |
|
|
|
Hi Dennis,
I will just explain showing you a small part of my transformation:
I have two stereotypes: View and Perspective. They both have a few attributes (Name, icon, etc...) which are of the type String, so I can set the value without a problem. Then Perspective has one more attribute caled Views which is a list of classes with the stereotype View.
So then if I try to set this value in the normal do section where I transform classes with the Perspective stereotype it won't work as intended because some classes o the type View won't yet be stereotyped and therefore won't show in the 'Views' property, since all these profile applications are done in the 'Do' section of the rules I think there's no way to know for sure which one gets run first, therefore I think that the only way to know for sure that all stereotypes have been applied is at the endpoint rule (so that's why I do most of the code there).
I hope I explained it properly, but it is a bit tricky and difficult to explain maybe so if you need to know something else just let me know, also note that here I just talk about two stereotypes but I do actually have about 10 and might have more at some point.
thanks,
regards,
Javier
|
|
|
Re: EMFTVM avoiding using elements from the output model [message #1118797 is a reply to message #1118182] |
Fri, 27 September 2013 15:59   |
Eclipse User |
|
|
|
I see: if I understand correctly, you cannot set the stereotype value before the value has its own stereotype assigned. In that case, you can still use your endpoint rule. However, instead of iterating over the output model, you should iterate over either:
1. the input elements that map to the stereotyped value you need, or
2. the traces that contain the source-target relationships (http://wiki.eclipse.org/ATL/EMFTVM#Advanced_tracing)
If you create the stereotyped elements you want to assign in a normal matched rule, you can simply iterate over the corresponding source elements and use the resolve() method. If you use lazy rules, you can iterate over the traces generated by the corresponding lazy rule, and select the target values you want in that way.
Hint: if you want to know how you should navigate the traces model, first run your current transformation with the required settings to save your trace model to a file (http://wiki.eclipse.org/ATL/EMFTVM#Advanced_tracing). Then you can look into the file to see what the traces look like.
|
|
|
Re: EMFTVM avoiding using elements from the output model [message #1121133 is a reply to message #1118797] |
Mon, 30 September 2013 05:53   |
Eclipse User |
|
|
|
Hi Dennis,
that's exactly what I have been doing and it seems to work great.
I'm facing two more problem though:
1 - I'm generating some elements using a lazy rule, but I create them in my endpoint rule (depending on certain values I set on the stereotypes I need to create an Association) so I wanted to assign these elements to a certain package. The package is created in a matched rule, so I thought I could use resolveTemp() to get to it, but it is not working, here's my code:
rule Model {
from
s: UML2!Model in IN (
not s.oclIsUndefined() and not (s.name = 'root model') and not (s.name =
'externals') and not (s.name = 'source references')
)
to
t: UML2!Model (
[...]
),
[...]
),
[...]
),
wac: UML2!Package (
name <- 'workbenchActions'
,
-- packagedElement <- thisModule.xmlElements -> select(e | e.name = 'actionSet')->debug('ActionSets!')
-- -> collect(e | thisModule.WorkbenchActions(e))
packagedElement<- Sequence{thisModule.resolveTemp(XML!Element.allInstances()->select(e|e.name='actionSet').first(), 'wAction')}
),
[...]
)
The package I need is 'wac', so to call it I was trying to use thisModule.resolveTemp(thisModule.mainModel,'wac') but apparently that doesn't work so I don't know if there is any other way I could get the package.
2 - My second problem seems more tricky. Again I create an element in my endpoint rule by means of a lazy rule and this time it's of the type UML2!Property. So I want to set the type of this property to a type that exists in the output model, but not in the input model, how can I do this? The problem is that the element exists in an input XML model and it gets transformed to an UML2 element, so I'm not sure if I can target the traces or how could I do it.
Also, I'm not sure I should be creating elements through a lazy rule in the endpoint rule, is this somehow "illegal" in ATL or is it just not recommended or should there be no problem?
Thanks again for all your help Dennis, hopefully you know how to solve these issues too!
|
|
|
Re: EMFTVM avoiding using elements from the output model [message #1121540 is a reply to message #1121133] |
Mon, 30 September 2013 14:40   |
Eclipse User |
|
|
|
Op 30-09-13 11:53, Javier García schreef:
> 1 - I'm generating some elements using a lazy rule, but I create them in my
> endpoint rule (depending on certain values I set on the stereotypes I need to
> create an Association) so I wanted to assign these elements to a certain
> package. The package is created in a matched rule, so I thought I could use
> resolveTemp() to get to it, but it is not working, here's my code:
The matched rule is processed before the endpoint rule, so no traces generated
by the endpoint rule can be accessed. Here's the execution order:
1. Match all matched rules (including any lazy rule invocations)
2. Apply all matched rules (including any lazy rule invocations)
3. Post-apply all matched rules ("do" block) (including any lazy rule invocations)
4. Run the endpoint rule, if any (including any lazy rule invocations)
Note that I added " (including any lazy rule invocations)" at each stage. This
is because you can basically insert a lazy rule invocation anywhere. Even in
the "from" condition part, although that does not seem useful.
> 2 - My second problem seems more tricky. Again I create an element in my
> endpoint rule by means of a lazy rule and this time it's of the type
> UML2!Property. So I want to set the type of this property to a type that
> exists in the output model, but not in the input model, how can I do this? The
> problem is that the element exists in an input XML model and it gets
> transformed to an UML2 element, so I'm not sure if I can target the traces or
> how could I do it.
Your output model is empty at the start of your transformation, so your
transformation must have generated the UML Type that you want to assign
somewhere. Depending on how your transformation generated the Type element,
you can find it back through either:
1. Implicit tracing (matched rules, default output element)
2. thisModule.resolveTemp() (matched rules, non-default output element)
3. Calling a unique lazy rule again (same output is returned)
4. Using reflection on thisModule.traces (lazy rules)
Note that you can elaborate option (4) by first trying to find the trace, and
if there is none, call the lazy rule. This strategy can also be useful for
unique lazy rules that are called recursively, and where you need the output
elements of the rule before the rule returns.
> Also, I'm not sure I should be creating elements through a lazy rule in the
> endpoint rule, is this somehow "illegal" in ATL or is it just not recommended
> or should there be no problem?
It's perfectly legal in ATL, but you should remember the execution order
stated above. Any traces generated as late as in the endpoint rule cannot be
accessed from matched rules.
|
|
|
Re: EMFTVM avoiding using elements from the output model [message #1122222 is a reply to message #1121540] |
Tue, 01 October 2013 06:44   |
Eclipse User |
|
|
|
Hi Dennis, thanks a lot, this is really useful and I'll be testing it these days and let you know how it goes.
I do have a couple more problems:
First one is that after reading you in this thread I think shouldn't be happening, so I'll explain:
As you told me in one of the earlier threads I should be able to give an stereotype to classes generated in lazy rules, but that was not the case in my transformation as I was getting errors so I have to apply the stereotype in the endpoint rule.
Here is the code:
rule Model {
from
s: UML2!Model in IN (
not s.oclIsUndefined() and not (s.name = 'root model') and not (s.name =
'externals') and not (s.name = 'source references')
)
to
t: UML2!Model (
name <- s.name ,
visibility <- s.visibility,
viewpoint <- s.viewpoint,
eAnnotations <- s.eAnnotations,
ownedComment <- s.ownedComment,
clientDependency <- s.clientDependency,
nameExpression <- s.nameExpression,
elementImport <- s.elementImport,
packageImport <- s.packageImport,
ownedRule <- s.ownedRule,
templateParameter <- s.templateParameter,
templateBinding <- s.templateBinding,
ownedTemplateSignature <- s.ownedTemplateSignature,
packageMerge <- s.packageMerge,
packagedElement <- s.packagedElement.union(Sequence {pck})
),
[...]
),
tool: UML2!Package (
name <- 'Toolbars'
,
packagedElement <- thisModule.toolbarsHelper->select(e|e.isClass() and not e.isInterface()) ->collect(e|thisModule.lazyToolbarClass(e)).union(
thisModule.toolbarsHelper->select(e|not e.isClass() and not e.isInterface()) ->collect(e|thisModule.lazyToolbarClass(e))).union(
thisModule.toolbarsHelper->select(e|e.isInterface()) ->collect(e|thisModule.lazyToolbarInterface(e)))
)
do {
thisModule.mainModel<-s;
--- We apply the profile and the Workbench stereotype.
t.applyProfile(profile!Profile.allInstances().asSequence().first())->debug('profile');
t.applyStereotype(profile!Stereotype.allInstances().asSequence() -> select(i | i.
qualifiedName = 'RCP::Workbench').last());
[...]
}
This is the model that calls the lazy rules, and here are the lazy rules:
lazy rule lazyToolbarClass {
from
s: XML!Element in Plugin
using {
nameValue : String = s.getElementName();
}
to
r: UML2!Class (
name <- nameValue
)
do {
thisModule.transformedToolbars <-thisModule.transformedToolbars.union(Sequence{r});
thisModule.wbactions <-thisModule.wbactions.union(r.setGroup(nameValue));
r;
}
}
lazy rule lazyToolbarInterface {
from
s: XML!Element in Plugin
to
r: UML2!Interface (
name <- s.getElementName()
)
--- The stereotype can't be applied since the element is generated outside
--- the model.
do {
thisModule.transformedToolbars <-thisModule.transformedToolbars.union(Sequence{r});
r;
}
}
So if I try to add to any of these lazy rules in the do section something like:
r.applyStereotype(profile!Stereotype.allInstances().asSequence() -> select(i | i.
qualifiedName = 'RCP::Toolbar').last());
then I get a java.lang.IllegalArgumentException.
My guess is that maybe the DO section from the lazyToolbar rule is done before the DO section of the Model matched rule, and therefore even though the Toolbar gets generated in the right place, the profile hasn't been yet applied to the model and no stereotypes can be applied, is this right?
Second problem:
This time it's similar to what I mentioned in this other thread here ( http://www.eclipse.org/forums/index.php/t/521205/ )and the thing is that the values of the stereotyped classes don't get transformed, but copies, therefore my output transformation is referencing the input transformation.
what would be the proper way to do this? as suggested in the other thread I checked this other thread ( http://www.eclipse.org/forums/index.php/mv/msg/452702/1010024/#msg_1010024 ) but I can't see a way to fix this right now.
Thanks a lot for all your help Dennis, and sorry for giving so much trouble but I think I'm getting to understand EMFTVM better and so far it seems faster than the regular ATL VM.
Regards,
Javier
|
|
| |
Re: EMFTVM avoiding using elements from the output model [message #1124114 is a reply to message #1122370] |
Thu, 03 October 2013 03:43   |
Eclipse User |
|
|
|
Hi Dennis,
thanks for your help but sadly I can't do that because here you can see the toolbarsHelper:
helper def: toolbarsHelper: Sequence (XML!Element) = thisModule.xmlElements
-> select(e | e.name ='viewContribution' or e.name='actionSet' or e.name='objectContribution');
and the problem is I have a matched rule for elements that are 'viewContribution', another for 'actionSet' and another for 'objectContribution', so it won't be as easy. I'll work on it as I think my problems would be fixed if I can change that.
Now I got a different error when using resolveTemp. Here is my transformation:
create OUT: UML2 from IN: UML2, Initial: UML2, Plugin: XML, Profile: profile;
helper def: initialClasses: Sequence(UML2!Class) =
UML2!Class.allInstancesFrom('Initial');
helper context UML2!Class def: getOwnedAttributes(): Sequence(UML2!Property) =
if thisModule.initialClasses -> select(e | e.name = self.name).isEmpty() then
Sequence{}
else
if not (thisModule.initialClasses -> select(e | e.name = self.name).first().
getAllAttributes().isEmpty()) then
thisModule.initialClasses -> select(e | e.name = self.name).first().
getAllAttributes()
else
Sequence{}
endif
endif;
[...]
rule ClassFromIN {
from
s: UML2!Class in IN (
s.oclIsTypeOf(UML2!"uml::Class")
and not s.oclIsUndefined()
)
to
t: UML2!"uml::Class" (
name <- s.name,
visibility <- s.visibility,
isLeaf <- s.isLeaf,
isAbstract <- s.isAbstract,
isActive <- s.isActive,
eAnnotations <- s.eAnnotations,
ownedComment <- s.ownedComment,
clientDependency <- s.clientDependency,
nameExpression <- s.nameExpression,
elementImport <- s.elementImport,
packageImport <- s.packageImport,
ownedRule <- s.ownedRule,
templateParameter <- s.templateParameter,
templateBinding <- s.templateBinding,
ownedTemplateSignature <- s.ownedTemplateSignature,
generalization <- s.generalization,
powertypeExtent <- s.powertypeExtent,
redefinedClassifier <- s.redefinedClassifier,
substitution <- s.substitution,
representation <- s.representation,
collaborationUse <- s.collaborationUse,
ownedUseCase <- s.ownedUseCase,
useCase <- s.useCase,
ownedAttribute <- s.ownedAttribute,
ownedConnector <- s.ownedConnector,
ownedBehavior <- s.ownedBehavior,
classifierBehavior <- s.classifierBehavior,
interfaceRealization <- s.interfaceRealization,
nestedClassifier <- s.nestedClassifier
ownedReception <- s.ownedReception
)
---Keeps the applied stereotypes and values(CURRENTLY NOT WORKING)
do {
t.ownedOperation <- s.getOwnedOperations()->debug('OwnedOperations') -> collect(e | thisModule.
resolveTemp(e, 't'));
t.ownedAttribute <- s.getOwnedAttributes()->debug('OwnedAttributtes')
-> collect(e | thisModule.
resolveTemp(e->debug('e'), 'tgt'));
}
rule PropertyFromInitial {
from
src: UML2!Property in Initial (
---We need to make sure that the property is not empty,and also
---that it doesn't belong to a type that is not transformed.
if src.refImmediateComposite().oclIsTypeOf(UML2!Class) then
src.refImmediateComposite().existsInIN() and not thisModule.inClasses ->
select(e | e.name = src.refImmediateComposite().name).first().
belongsToPackage('google') and if src.type.oclIsUndefined() then
false
else
if src.type.getModel().oclIsUndefined() then
true
else
not (src.type.getModel().name = UML2!Model.
allInstancesFrom('IN').first().name)
endif
endif
else
false
endif
)
to
tgt: UML2!Property (
name <- src.name,
visibility <- src.visibility,
lower <- src.lower,
upper <- src.upper,
type <- src.setType(),
aggregation <- src.aggregation,
association <- src.association,
isStatic <- src.isStatic,
ownedComment <- src.ownedComment
)
}
So, as you can see I transform the properties and I transform the classes.
Then on the do section I use resolveTemp to assign these transformed properties to the correspondent classes, and that's when I get this exception:
Quote:
org.eclipse.m2m.atl.emftvm.util.VMException: Cannot resolve default trace target 'tgt' for org.dews_online.ccui.core.view.viewparts.PhenomenonTreeView.viewerContribution:UML2!Property
at static EMFTVM!ExecEnv::resolveTemp(var: Object, target_pattern_name: String) : Object(OCL)
Local variables: [org.dews_online.ccui.core.view.viewparts.PhenomenonTreeView.viewerContribution:UML2!Property, 'tgt']
at rule ClassFromIN@postApply@1#5(platform:/resource//ATLTesting/EMFTVMTest/Transformations/Third/EMFTVMThird.atl#[235:19-236:39])
Local variables: [e = org.dews_online.ccui.core.view.viewparts.PhenomenonTreeView.viewerContribution:UML2!Property]
at public org.eclipse.m2m.atl.emftvm.util.LazyList org.eclipse.m2m.atl.emftvm.util.LazyList.collect(org.eclipse.m2m.atl.emftvm.CodeBlock)
Local variables: []
at rule ClassFromIN@postApply#17(platform:/resource//ATLTesting/EMFTVMTest/Transformations/Third/EMFTVMThird.atl#[234:4-236:41])
Local variables: [__trace__: TRACE!TraceLink = 933c0c:TRACE!TraceLink, s: UML2!Class = MapElementsView:UML2!Class, t: UML2!uml::Class = MapElementsView:UML2!Class]
at static EMFTVM!ExecEnv::main() : Object(platform:/resource//ATLTesting/EMFTVMTest/Transformations/Third/EMFTVMThird.atl)
Local variables: []
That transformation did work on normal ATL, so I don't know what is the issue here, I don't really understand it because I am transforming the properties the same way in both normal ATL and EMFTVM, as always any help is welcome.
thanks again,
regards,
Javier
|
|
| | |
Re: EMFTVM avoiding using elements from the output model [message #1128114 is a reply to message #1124478] |
Mon, 07 October 2013 06:58   |
Eclipse User |
|
|
|
Ok thanks a lot for all your help Dennis, I managed to get over all my issues and my transformation works perfectly now.
Just one little thing I want to ask, though I'm not sure if I should open a new post for this but anyways, what's the way to transform associations in EMFTVM?
I ask because I always used to do something like:
lazy rule createAssociation {
from
s: String, s2: String
to
tgt: UML2!Association (
ownedEnd <- Sequence{thisModule.createProperty(tgt,s,true)},
memberEnd<-Sequence{thisModule.createProperty(tgt,s2,false)}
)
do{
tgt;
}
}
BUT apparently ownedEnd and memberEnd are the same list, so what this was doing was overwrite the list with the last element I used (in this case memberEnd), so I had to do this instead:
lazy rule createAssociation {
from
s: String, s2: String
to
tgt: UML2!Association (
ownedEnd <- Sequence{thisModule.createProperty(tgt,s,true),thisModule.createProperty(tgt,s2,false)}
)
do{
tgt;
}
}
It took me quite a while until I understood why this was happening, so I think it just happens due to the difference in regular ATL and EMFTVM on handling these things, as in normal ATL assigning a new value to a list in a transformation seemed to just make an union of both lists but in EMFTVM it seems to replace it.
So not sure if this is intended to work this way or if it is a bug or just a result of the way EMFTVM works, but anyways all my problems seem fixed so far, so thanks for all your help!
|
|
|
Re: EMFTVM avoiding using elements from the output model [message #1129064 is a reply to message #1128114] |
Tue, 08 October 2013 04:48  |
Eclipse User |
|
|
|
ATL/EMFTVM always uses "set" semantics for assigning to properties, while regular ATL uses "set" for single-valued properties and "add" for multi-valued properties (collections). ATL/EMFTVM chooses "set" - even for collections - because that offers better control when overriding property assignments in sub-rules.
|
|
|
Goto Forum:
Current Time: Tue Jul 22 18:59:00 EDT 2025
Powered by FUDForum. Page generated in 0.05415 seconds
|