Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » QVT-OML » Cannot add stereotypes when launching the QVTo transform programmatically from Java(I provide a minimal example to try out. Any help on how to make it work?)
Cannot add stereotypes when launching the QVTo transform programmatically from Java [message #1741285] Wed, 24 August 2016 10:59 Go to next message
Matteo M. is currently offline Matteo M.Friend
Messages: 40
Registered: May 2012
Member
Hi all,
I have a QVTo transform that operates on an 'inout' UML model. The transformation adds UML artifacts to an existing UML model and applies them SysML stereotypes. It's invoked programmatically from Java code. In my test case, I use a right-click menu in the run-time instance, see the attached minimal example projects to try out, test.m2m, test.executor and TestSandboxModel.zip (place this one in the workspace for the runtime instance). My environment is Eclipse Modeling Tools Version: Neon Release (4.6.0) Build id: 20160613-1800.

The problem is that I'm not able to apply stereotypes to model elements. More specifically, after using
element.applyStereotype(stereotype);

to apply a stereotype to an element in QVTo, the following assertion fails
assert fatal (element.isStereotypeApplied(stereotype));


The attached example project (TestSandboxModel.zip) is a simple SysML model with a 'Block' and a 'FlowPort' in its root element (TestSandboxModel.zip). For quick reference, here's the QVTo transform, that adds a Port to the Class in the model and applies the 'FlowPort' stereotype to it.
modeltype UML uses 'http://www.eclipse.org/uml2/5.0.0/UML';

transformation SimpleUmlIncrementalMod(inout uml:UML);

property umlModel = uml.rootObjects()![Model];
property FlowPortStereotype = umlModel.getAppliedProfiles().ownedStereotype![name = 'FlowPort'];

main()
{
    log('SimpleUmlIncrementalMod Transformation Started');
    log('');
    // get the class
    var clz := umlModel.allSubobjectsOfKind(Class)![Class];
    // create new port
    var prt := object Port {name := 'xyz';};
    // add it to the class
    clz.ownedAttribute += prt;
    // apply stereotype
    applyStereotypeAndCheck(prt, FlowPortStereotype);
    log('');
    log('Transformation ended.');
}

helper applyStereotypeAndCheck(inout element : Element, in stereotype : Stereotype)
{
    assert fatal (element.isStereotypeApplicable(stereotype))
        with log('Stereotype ' + stereotype.qualifiedName + ' is not applicable to element ' + element.repr());
    var xx := element.applyStereotype(stereotype);
    log('       Returned ecore::EObject repr() is ' + xx.repr());
    assert fatal (element.isStereotypeApplied(stereotype))
        with log('Stereotype ' + stereotype.qualifiedName + ' hasnt been applied to element ' + element.repr());
    log('       Applied the stereotype ' + stereotype.qualifiedName);
    log('');
}


And here's is the Java code that calls the transform executor.
package test.executor;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.List;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.impl.EPackageRegistryImpl;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.m2m.qvt.oml.BasicModelExtent;
import org.eclipse.m2m.qvt.oml.ExecutionContextImpl;
import org.eclipse.m2m.qvt.oml.ExecutionDiagnostic;
import org.eclipse.m2m.qvt.oml.ModelExtent;
import org.eclipse.m2m.qvt.oml.TransformationExecutor;
import org.eclipse.m2m.qvt.oml.util.Log;
import org.eclipse.m2m.qvt.oml.util.WriterLog;
import org.eclipse.papyrus.sysml.portandflows.PortandflowsPackage;
import org.eclipse.uml2.uml.UMLPackage;

public class SimpleUmlIncrementalModExecutor {

    public static void run(String path)
    {
        // Refer to an existing transformation via URI
        URI transformationURI = URI.createURI("platform:/plugin/test.m2m/transforms/SimpleUmlIncrementalMod.qvto");
        //
        // metamodels
        EPackage.Registry registry = new EPackageRegistryImpl(EPackage.Registry.INSTANCE);
        UMLPackage theUMLPackage = (UMLPackage)EPackage.Registry.INSTANCE.getEPackage(UMLPackage.eNS_URI);
        PortandflowsPackage thePortandflowsPackage=(PortandflowsPackage)EPackage.Registry.INSTANCE.getEPackage(PortandflowsPackage.eNS_URI);
        registry.put(theUMLPackage.getNsURI(), theUMLPackage);
        registry.put(thePortandflowsPackage.getNsURI(), thePortandflowsPackage);
        // create executor for the given transformation
        TransformationExecutor executor = new TransformationExecutor(transformationURI, registry);
        //
        // define the transformation inout
        // Remark: we take the objects from a resource, however
        // a list of arbitrary in-memory EObjects may be passed
        ResourceSet resourceSet = new ResourceSetImpl();
        EList<EObject> inOutObjects = resourceSet
                                .getResource(URI.createFileURI(path),true)
                                    .getContents();
        //
        // create the inout extent with its initial content
        ModelExtent inout = new BasicModelExtent(inOutObjects);
        //
        // setup the execution environment details -> 
        // configuration properties, logger, monitor object etc.
        OutputStreamWriter outStream = new OutputStreamWriter(System.out);
        Log log = new WriterLog(outStream);
        ExecutionContextImpl context = new ExecutionContextImpl();
        context.setConfigProperty("keepModeling", true);
        context.setLog(log);
        //
        // run the transformation assigned to the executor with the given 
        // input and output and execution context -> ChangeTheWorld(in, out)
        // Remark: variable arguments count is supported
        ExecutionDiagnostic result = executor.execute(context, inout);
        //
        // check the result for success
        if(result.getSeverity() == Diagnostic.OK)
        {
            // This list contains all the objects from the initial ModelExtent, plus all the ones
            // which were created during the QVTo transformations.
            List<EObject> inOutObjects2 = inout.getContents();
            resourceSet.getResource(URI.createFileURI(path),true)
                .getContents().addAll(inOutObjects2);
            try
            {
                resourceSet.getResource(URI.createFileURI(path),true)
                    .save(Collections.emptyMap());
            } catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        else
        {
            // turn the result diagnostic into status and send it to error log
            IStatus status = BasicDiagnostic.toIStatus(result);
            Activator.getDefault().getLog().log(status);
        }

    }

}


Additional considerations:


  • If I just execute the QVTo transform in standalone mode (using Run Configuration to configure the inout arg), it works.
  • If i do not apply the 'FlowPort' stereotype --i.e., I remove/comment the applyStereotypeAndCheck(prt, FlowPortStereotype); in the QVTo transform-- the Port 'xyz' is added to the Class in both cases (standalone execution and programmatic invokation from Java)
  • when the transform is invoked from Java and applyStereotypeAndCheck() is executed, the following happens:

    • the stereotype seems to be correctly applied; this log message is displayed in the console
      Returned ecore::EObject repr() is org.eclipse.papyrus.sysml.portandflows.internal.impl.FlowPortImpl@5df1ee9f (isConjugated: false, direction: inout)

    • the 2nd assert statement fails, that checks for the actual stereotype application; I see the following log message:
      ASSERT [fatal] failed at (SimpleUmlIncrementalMod.qvto:30) : Stereotype SysML::PortAndFlows::FlowPort hasnt been applied to element org.eclipse.uml2.uml.internal.impl.PortImpl@4d496696 (name: xyz, visibility: <unset>) (isLeaf: false) (isStatic: false) (isOrdered: false, isUnique: true, isReadOnly: false) (aggregation: none, isDerived: false, isDerivedUnion: false, isID: false) (isBehavior: false, isConjugated: false, isService: true)
      Terminating execution...
      org.eclipse.m2m.internal.qvt.oml.evaluator.QvtAssertionFailed: Stereotype SysML::PortAndFlows::FlowPort hasnt been applied to element org.eclipse.uml2.uml.internal.impl.PortImpl@4d496696 (name: xyz, visibility: <unset>) (isLeaf: false) (isStatic: false) (isOrdered: false, isUnique: true, isReadOnly: false) (aggregation: none, isDerived: false, isDerivedUnion: false, isID: false) (isBehavior: false, isConjugated: false, isService: true)
      	at SimpleUmlIncrementalMod::applyStereotypeAndCheck(SimpleUmlIncrementalMod.qvto:31)
      	at SimpleUmlIncrementalMod::main(SimpleUmlIncrementalMod.qvto:19)
      ...




Given that it works in standalone mode, I suppose it's due to how I call the transform programmatically from Java. Any hint?

Thank you in advance for your help.
--
Matteo

[Updated on: Wed, 24 August 2016 11:02]

Report message to a moderator

Re: Cannot add stereotypes when launching the QVTo transform programmatically from Java [message #1741404 is a reply to message #1741285] Wed, 24 August 2016 19:39 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 5633
Registered: July 2009
Senior Member
Hi

Stereotypes can be a PITA. The problem is usually only obvious with hindsight...

Since it works standalone, you can single step two debugging sessions to see where and so why the behavior deviates. Another PITA but eventually you get there.

Regards

Ed Willink
Re: Cannot add stereotypes when launching the QVTo transform programmatically from Java [message #1741854 is a reply to message #1741285] Tue, 30 August 2016 08:04 Go to previous message
Christopher Gerking is currently offline Christopher GerkingFriend
Messages: 57
Registered: April 2011
Member
Hi

When executing QVTo from Java, the Java code generated from the UML metamodel is used to create/modify models. This code enforces that a stereotype can only be applied to a model element if it has a) a proper container, and b) the corresponding profile has been applied to the container element. This is a sort of business logic of the UML metamodel, certainly not a misbehavior of QVTo. When running in debug mode, the generated Java code is not used and, therefore, the constraint does not apply.


Kind regards
Christopher
Previous Topic:Metemodel registry
Next Topic:Passing external variables from eclipse
Goto Forum:
  


Current Time: Wed Feb 21 17:33:52 GMT 2018

Powered by FUDForum. Page generated in 0.01798 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software