Home » Modeling » ATL » EMFTVM: Transformation not terminating in Standalone Mode
EMFTVM: Transformation not terminating in Standalone Mode [message #1738342] |
Tue, 19 July 2016 07:59 |
Sven L. Messages: 16 Registered: May 2012 |
Junior Member |
|
|
Hello,
I wrote a refining transformation that would create a custom trace model as second output.
For this purpose I created a simple Trace metamodel which just contains a trace root container and a trace class, that stores a source and a target value, both Strings.
During the transformations I would create trace elements, which I add to the container through an endpoint rule, to make sure all the elements are created.
When the transformation is run in my eclipse it terminates in 0.5 seconds. When it's run in a standalone application it does not terminate at all (been running > 5 min now)
I suspect it's the endpoint rule that causes the trouble, but I don't know why. Here's the code:
-- @atlcompiler emftvm
-- @nsURI EMFTVM=http://www.eclipse.org/m2m/atl/2011/EMFTVM
-- @path NodeSet=/metamodel/NodeSet.ecore
-- @path Trace=/metamodel/MyTrace.ecore
module ChangeNodeId;
create OUT: NodeSet, TRACE: MyTrace refining IN: NodeSet;
helper def : traceList : Sequence(MyTrace!Trace) = Sequence{};
helper def : traceModel : MyTrace!Traces = OclUndefined;
-- root rule: create trace container
rule Traces {
from
s : NodeSet!NodeSetType
to
t : NodeSet!NodeSetType,
traceModel : MyTrace!Traces
do {
thisModule.traceModel <- traceModel;
}
}
-- change something, create trace of change
rule ChangeNodeId {
from
s : NodeSet!Variable
to
t : NodeSet!Variable (
nodeId <- thisModule.generateNodeId(source.nodeId)
),
trace : MyTrace!Trace (
source <- source.nodeId
)
do {
trace.target <- target.nodeId;
thisModule.traceList <- thisModule.traceList -> append(trace);
}
}
-- add traces to container
endpoint rule addTraces() {
do {
thisModule.traceModel.traces <- thisModule.traceList;
}
}
When I remove the endpoint rule the transformation also terminates in standalone mode, but now I don't know, how I can add the created traces to the container. I also tried something like this: I would like to iterate over all source elements, get the trace (if one was created), and add it to the container.
-- root rule: create trace container
rule Traces {
from
s : NodeSet!NodeSetType
to
t : NodeSet!NodeSetType,
traceModel : MyTrace!Traces (
traces <- NodeSet!Node.allInstances() -> select(i | not thisModule.resolveTemp(i, 'trace').oclIsUndefined()) -> collect(e | thisModule.resolveTemp(e, 'trace'))
)
}
but here I can't figure out how to find the created traces. This throws an VMException: Cannot resolve default trace target, when not every element has a trace.
I could obviously make it mandatory to create a trace for every source element, but I would rather look for another solution first.
[Updated on: Tue, 19 July 2016 08:01] Report message to a moderator
|
|
|
Re: EMFTVM: Transformation not terminating in Standalone Mode [message #1738498 is a reply to message #1738342] |
Wed, 20 July 2016 11:09 |
|
First of all, let's look into the reason why your standalone setup behaves different from the Eclipse setup. Can you post a thread dump of the Java thread that executes the transformation?
Second: do you really need your own custom trace model? If the EMFTVM trace model suffices, you can simply save it by adding a "trace" in/out model to your launch config.
Third: your programming style is a rewriting style, where you update the model/execution state incrementally. ATL is a mapping style language, that works best by assigning values only once. Updating global helper attributes multiple times makes your transformation more complex. Your second attempt with thisModule.resolveTemp() follows the recommended ATL programming style, but is complicated by having to repeat the ChangeNodeId rule's filter expression. The simplest way to deal with this is to extract the ChangeNodeId rule's filter expression into a helper attribute defined on the rule's source element, so that you can reuse the same helper attribute in the Traces rule. Alternatively, you can use trace model reflection to iterate over all rule applications.
Cheers,
Dennis
|
|
|
Re: EMFTVM: Transformation not terminating in Standalone Mode [message #1738505 is a reply to message #1738498] |
Wed, 20 July 2016 12:29 |
Sven L. Messages: 16 Registered: May 2012 |
Junior Member |
|
|
Hi Dennis,
thank you for your reply.
1) Since I was running the transformation in an OSGi environment I didn't notice that it's actually indeed terminating. If I run it as a java application I can see that it throws a StackOverflowException.
Exception in thread "main" java.lang.StackOverflowError
at org.eclipse.m2m.atl.emftvm.util.LazyCollection$AppendIterator.<init>(LazyCollection.java:406)
at org.eclipse.m2m.atl.emftvm.util.LazyList$AppendList.iterator(LazyList.java:383)
at org.eclipse.m2m.atl.emftvm.util.OCLOperations$ResolveList$ResolveIterator.<init>(OCLOperations.java:69)
at org.eclipse.m2m.atl.emftvm.util.OCLOperations$ResolveList.iterator(OCLOperations.java:119)
at org.eclipse.m2m.atl.emftvm.util.LazyCollection$WrappedIterator.<init>(LazyCollection.java:90)
at org.eclipse.m2m.atl.emftvm.util.LazyCollection$AppendIterator.<init>(LazyCollection.java:407)
at org.eclipse.m2m.atl.emftvm.util.LazyList$AppendList.iterator(LazyList.java:383)
at org.eclipse.m2m.atl.emftvm.util.OCLOperations$ResolveList$ResolveIterator.<init>(OCLOperations.java:69)
at org.eclipse.m2m.atl.emftvm.util.OCLOperations$ResolveList.iterator(OCLOperations.java:119)
at org.eclipse.m2m.atl.emftvm.util.LazyCollection$WrappedIterator.<init>(LazyCollection.java:90)
at org.eclipse.m2m.atl.emftvm.util.LazyCollection$AppendIterator.<init>(LazyCollection.java:407)
at org.eclipse.m2m.atl.emftvm.util.LazyList$AppendList.iterator(LazyList.java:383)
Again, if I remove the endpoint rule, everything works just fine.
2) Yes, I think I do. I want to keep track of attributes that changed. With the EMFTVM trace model I can only find out which object changed, but not which value the attribute of the element had before it was changed. (In this simple case above, I want to keep track of the change on the NodeId Attribute)
Of course, if you are aware of a better way to achieve this, please let me know.
3) Yes, I'm aware of that. While looking into custom traces I found this solution: https://wiki.eclipse.org/ATL/Design_Patterns#Custom_Tracing. I tried to follow this idea and just use it as second output model (encapsulated in my simple trace model).
Quote:The simplest way to deal with this is to extract the ChangeNodeId rule's filter expression into a helper attribute defined on the rule's source element, so that you can reuse the same helper attribute in the Traces rule
This is a good idea. Will this also work if other rules would create traces as well? I fear this might get very confusing and I feel like using the trace model reflection might be the cleanest way. I will look into both options.
|
|
|
Re: EMFTVM: Transformation not terminating in Standalone Mode [message #1738644 is a reply to message #1738505] |
Thu, 21 July 2016 15:52 |
|
1) The StackOverflowException is not an infinite loop in this case, but caused by too deep recursion into the lazy list structure built in the ChangeNodeId rule. On every binding, each element in the list is resolved to its target element, and this list only contains target elements already(!). You can use the <:= assignment operator instead of the binding operator to skip the source-to-target resolution step:
-- change something, create trace of change
rule ChangeNodeId {
from
s : NodeSet!Variable
to
t : NodeSet!Variable (
nodeId <- thisModule.generateNodeId(source.nodeId)
),
trace : MyTrace!Trace (
source <- source.nodeId
)
do {
trace.target <- target.nodeId;
thisModule.traceList <:= thisModule.traceList -> append(trace);
}
}
-- add traces to container
endpoint rule addTraces() {
do {
thisModule.traceModel.traces <:= thisModule.traceList;
}
}
That said, EMFTVM's lazy collection implementation isn't very efficient in applying many operations to a single collection; all (simple) operations are kept in a chain of wrappers around the initial collection, and an attempt to iterate the collection will instantiate a similar chain of wrapped iterators.
Cheers,
Dennis
|
|
|
Re: EMFTVM: Transformation not terminating in Standalone Mode [message #1738653 is a reply to message #1738644] |
Thu, 21 July 2016 17:09 |
|
2) Ok, when you use refining mode, you can indeed not keep a trace reference to the original source element, and therefore you no longer have the original attribute values. You need custom tracing.
3) You could use trace model reflection in the Traces rule as follows:
-- root rule: create trace container
rule Traces {
from
s : NodeSet!NodeSetType
to
t : NodeSet!NodeSetType,
traceModel : MyTrace!Traces (
traces <- thisModule.traces.rules
->collect(r | r.links
->collect(l | l.targetElements
->select(te | te.name = 'trace')
->collect(te | te.object)
)
)->flatten()
)
}
Cheers,
Dennis
|
|
| | |
Goto Forum:
Current Time: Thu Sep 26 00:32:41 GMT 2024
Powered by FUDForum. Page generated in 0.03873 seconds
|