Home » Modeling » ATL » Calling EMFTVM programmatically error
Calling EMFTVM programmatically error [message #1695017] |
Mon, 11 May 2015 12:23 |
Rafael Durelli Messages: 72 Registered: September 2012 |
Member |
|
|
Hello guys,
I'm trying to calling an ATL programmatically using the EMFTVM. The created ATL works fine in the Eclipse Plug-ing. However, when I tried to call it programmatically it generates an empty xmi file. Bellow there is the source-code that i'm using to call the ATL (EMFTVM) programmatically.
public class ATLLauncher {
// Some constants for quick initialization and testing.
public final static String IN_METAMODEL = "./metamodels/KDM.ecore";
public final static String IN_METAMODEL_NAME = "MM";
public final static String OUT_METAMODEL = "./metamodels/KDM.ecore";
public final static String OUT_METAMODEL_NAME = "MM";
public final static String IN_MODEL = "./models/TesteLucas_kdm.xmi";
public final static String OUT_MODEL = "./models/TesteLucas_kdmFuncionou.xmi";
public final static String TRANSFORMATION_DIR = "./transformations/";
public final static String TRANSFORMATION_MODULE= "renameTESTE";
// The input and output metamodel nsURIs are resolved using lazy registration of metamodels, see below.
private String inputMetamodelNsURI;
private String outputMetamodelNsURI;
//Main transformation launch method
public void launch(String inMetamodelPath, String inModelPath, String outMetamodelPath,
String outModelPath, String transformationDir, String transformationModule){
/*
* Creates the execution environment where the transformation is going to be executed,
* you could use an execution pool if you want to run multiple transformations in parallel,
* but for the purpose of the example let's keep it simple.
*/
ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
ResourceSet rs = new ResourceSetImpl();
/*
* Load meta-models in the resource set we just created, the idea here is to make the meta-models
* available in the context of the execution environment, the ResourceSet is later passed to the
* ModuleResolver that is the actual class that will run the transformation.
* Notice that we use the nsUris to locate the metamodels in the package registry, we initialize them
* from Ecore files that we registered lazily as shown below in e.g. registerInputMetamodel(...)
*/
Metamodel inMetamodel = EmftvmFactory.eINSTANCE.createMetamodel();
inMetamodel.setResource(rs.getResource(URI.createURI(inputMetamodelNsURI), true));
env.registerMetaModel(IN_METAMODEL_NAME, inMetamodel);
Metamodel outMetamodel = EmftvmFactory.eINSTANCE.createMetamodel();
outMetamodel.setResource(rs.getResource(URI.createURI(outputMetamodelNsURI), true));
env.registerMetaModel(OUT_METAMODEL_NAME, outMetamodel);
/*
* Create and register resource factories to read/parse .xmi and .emftvm files,
* we need an .xmi parser because our in/output models are .xmi and our transformations are
* compiled using the ATL-EMFTV compiler that generates .emftvm files
*/
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl());
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml", new XMLResourceFactoryImpl());
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("emftvm", new EMFTVMResourceFactoryImpl());
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new EcoreResourceFactoryImpl());
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/kdm", KdmPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/action", ActionPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/build", BuildPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/code", CodePackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/conceptual", ConceptualPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/core", CorePackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/platform", PlatformPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/data", DataPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/event", EventPackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/source", SourcePackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/structure", StructurePackageImpl.eINSTANCE);
rs.getPackageRegistry().put("http://www.eclipse.org/MoDisco/kdm/ui", UiPackageImpl.eINSTANCE);
// Load models
Model inModel = EmftvmFactory.eINSTANCE.createModel();
inModel.setResource(rs.getResource(URI.createURI(inModelPath, true), true));
env.registerInputModel("IN", inModel);
Model outModel = EmftvmFactory.eINSTANCE.createModel();
outModel.setResource(rs.createResource(URI.createURI(outModelPath)));
env.registerOutputModel("OUT", outModel);
/*
* Load and run the transformation module
* Point at the directory your transformations are stored, the ModuleResolver will
* look for the .emftvm file corresponding to the module you want to load and run
*/
ModuleResolver mr = new DefaultModuleResolver(transformationDir, rs);
System.out.println("sou o MR " +mr);
TimingData td = new TimingData();
env.loadModule(mr, TRANSFORMATION_MODULE);
td.finishLoading();
env.run(td);
td.finish();
// Save models
try {
outModel.getResource().save(Collections.emptyMap());
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* I seriously hate relying on the eclipse facilities, and if you're not building an eclipse plugin
* you can't rely on eclipse's registry (let's say you're building a stand-alone tool that needs to run ATL
* transformation, you need to 'manually' register your metamodels)
* This method does two things, it initializes an Ecore parser and then programmatically looks for
* the package definition on it, obtains the NsUri and registers it.
*/
private String lazyMetamodelRegistration(String metamodelPath){
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
ResourceSet rs = new ResourceSetImpl();
// Enables extended meta-data, weird we have to do this but well...
final ExtendedMetaData extendedMetaData = new BasicExtendedMetaData(EPackage.Registry.INSTANCE);
rs.getLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
Resource r = rs.getResource(URI.createFileURI(metamodelPath), true);
EObject eObject = r.getContents().get(0);
// A meta-model might have multiple packages we assume the main package is the first one listed
if (eObject instanceof EPackage) {
EPackage p = (EPackage)eObject;
System.out.println(p.getNsURI());
EPackage.Registry.INSTANCE.put(p.getNsURI(), p);
return p.getNsURI();
}
return null;
}
/*
* As shown above we need the inputMetamodelNsURI and the outputMetamodelNsURI to create the context of
* the transformation, so we simply use the return value of lazyMetamodelRegistration to store them.
* -- Notice that the lazyMetamodelRegistration(..) implementation may return null in case it doesn't
* find a package in the given metamodel, so watch out for malformed metamodels.
*
*/
public void registerInputMetamodel(String inputMetamodelPath){
inputMetamodelNsURI = lazyMetamodelRegistration(inputMetamodelPath);
System.out.println("Meu Input " + inputMetamodelNsURI);
}
public void registerOutputMetamodel(String outputMetamodelPath){
outputMetamodelNsURI = lazyMetamodelRegistration(outputMetamodelPath);
System.out.println("Meu output " + outputMetamodelNsURI);
}
/*
* A test main method, I'm using constants so I can quickly change the case study by simply
* modifying the header of the class.
*/
public static void main(String ... args){
ATLLauncher l = new ATLLauncher();
l.registerInputMetamodel(IN_METAMODEL);
l.registerOutputMetamodel(OUT_METAMODEL);
l.launch(IN_METAMODEL, IN_MODEL, OUT_METAMODEL, OUT_MODEL, TRANSFORMATION_DIR, TRANSFORMATION_MODULE);
}
}
The ATL that I´m calling is:
-- @atlcompiler emftvm
-- @path MM=/ATLauncher/metamodels/KDM.ecore
module renameTESTE;
create OUT : MM refining IN : MM;
rule name {
from
s : MM!ClassUnit (s.name = 'Client')
to
target : MM!ClassUnit (
name <- 'RafaelChanged'
)
}
The output is the following xmi file :
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"/>
The files .asm and .emftvm were also created properly. Does anyone know how to fix this?
Thanks in advance.
|
|
|
Re: Calling EMFTVM programmatically error [message #1695124 is a reply to message #1695017] |
Tue, 12 May 2015 08:00 |
|
A few remarks:
- Your input metamodel and output metamodel are the same: you should load/register it only once
- Your metamodel is a generated Ecore metamodel, not dynamic metamodel: use KdmPackage.eINSTANCE.eResource() to load it, instead of referencing the ecore file
- You can use org.eclipse.m2m.atl.emftvm.util.EMFTVMUtil.registerEPackages(ResourceSet) to register all EPackages in a ResourceSet
Cheers,
Dennis
|
|
| |
Re: Calling EMFTVM programmatically error [message #1695223 is a reply to message #1695155] |
Tue, 12 May 2015 19:49 |
|
In code perhaps?
public class ATLLauncher {
// Some constants for quick initialization and testing.
public final static String METAMODEL_NAME = "MM";
public final static String IN_MODEL = "./models/TesteLucas_kdm.xmi";
public final static String OUT_MODEL = "./models/TesteLucas_kdmFuncionou.xmi";
public final static String TRANSFORMATION_DIR = "./transformations/";
public final static String TRANSFORMATION_MODULE= "renameTESTE";
// The input and output metamodel nsURIs are resolved using lazy registration of metamodels, see below.
private String inputMetamodelNsURI;
private String outputMetamodelNsURI;
//Main transformation launch method
public void launch(String inMetamodelPath, String inModelPath, String outMetamodelPath,
String outModelPath, String transformationDir, String transformationModule){
/*
* Creates the execution environment where the transformation is going to be executed,
* you could use an execution pool if you want to run multiple transformations in parallel,
* but for the purpose of the example let's keep it simple.
*/
ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
ResourceSet rs = new ResourceSetImpl();
/*
* Load meta-models in the resource set we just created, the idea here is to make the meta-models
* available in the context of the execution environment, the ResourceSet is later passed to the
* ModuleResolver that is the actual class that will run the transformation.
* Notice that we use the nsUris to locate the metamodels in the package registry, we initialize them
* from Ecore files that we registered lazily as shown below in e.g. registerInputMetamodel(...)
*/
Metamodel metamodel = EmftvmFactory.eINSTANCE.createMetamodel();
metamodel.setResource(KdmPackage.eINSTANCE.eResource());
env.registerMetaModel(IN_METAMODEL_NAME, metamodel);
/*
* Create and register resource factories to read/parse .xmi and .emftvm files,
* we need an .xmi parser because our in/output models are .xmi and our transformations are
* compiled using the ATL-EMFTV compiler that generates .emftvm files
*/
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl());
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xml", new XMLResourceFactoryImpl());
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("emftvm", new EMFTVMResourceFactoryImpl());
rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
// Load models
Model inModel = EmftvmFactory.eINSTANCE.createModel();
inModel.setResource(rs.getResource(URI.createURI(inModelPath, true), true));
env.registerInputModel("IN", inModel);
Model outModel = EmftvmFactory.eINSTANCE.createModel();
outModel.setResource(rs.createResource(URI.createURI(outModelPath)));
env.registerOutputModel("OUT", outModel);
/*
* Load and run the transformation module
* Point at the directory your transformations are stored, the ModuleResolver will
* look for the .emftvm file corresponding to the module you want to load and run
*/
ModuleResolver mr = new DefaultModuleResolver(transformationDir, rs);
System.out.println("sou o MR " +mr);
TimingData td = new TimingData();
env.loadModule(mr, TRANSFORMATION_MODULE);
td.finishLoading();
env.run(td);
td.finish();
// Save models
try {
outModel.getResource().save(Collections.emptyMap());
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* I seriously hate relying on the eclipse facilities, and if you're not building an eclipse plugin
* you can't rely on eclipse's registry (let's say you're building a stand-alone tool that needs to run ATL
* transformation, you need to 'manually' register your metamodels)
* This method does two things, it initializes an Ecore parser and then programmatically looks for
* the package definition on it, obtains the NsUri and registers it.
*/
private String lazyMetamodelRegistration(String metamodelPath){
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl());
ResourceSet rs = new ResourceSetImpl();
// Enables extended meta-data, weird we have to do this but well...
final ExtendedMetaData extendedMetaData = new BasicExtendedMetaData(EPackage.Registry.INSTANCE);
rs.getLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, extendedMetaData);
Resource r = rs.getResource(URI.createFileURI(metamodelPath), true);
EObject eObject = r.getContents().get(0);
// A meta-model might have multiple packages we assume the main package is the first one listed
if (eObject instanceof EPackage) {
EPackage p = (EPackage)eObject;
System.out.println(p.getNsURI());
EPackage.Registry.INSTANCE.put(p.getNsURI(), p);
return p.getNsURI();
}
return null;
}
/*
* As shown above we need the inputMetamodelNsURI and the outputMetamodelNsURI to create the context of
* the transformation, so we simply use the return value of lazyMetamodelRegistration to store them.
* -- Notice that the lazyMetamodelRegistration(..) implementation may return null in case it doesn't
* find a package in the given metamodel, so watch out for malformed metamodels.
*
*/
public void registerInputMetamodel(String inputMetamodelPath){
inputMetamodelNsURI = lazyMetamodelRegistration(inputMetamodelPath);
System.out.println("Meu Input " + inputMetamodelNsURI);
}
public void registerOutputMetamodel(String outputMetamodelPath){
outputMetamodelNsURI = lazyMetamodelRegistration(outputMetamodelPath);
System.out.println("Meu output " + outputMetamodelNsURI);
}
/*
* A test main method, I'm using constants so I can quickly change the case study by simply
* modifying the header of the class.
*/
public static void main(String ... args){
ATLLauncher l = new ATLLauncher();
l.registerInputMetamodel(IN_METAMODEL);
l.registerOutputMetamodel(OUT_METAMODEL);
l.launch(IN_METAMODEL, IN_MODEL, OUT_METAMODEL, OUT_MODEL, TRANSFORMATION_DIR, TRANSFORMATION_MODULE);
}
}
Cheers,
Dennis
|
|
| | | |
Re: Calling EMFTVM programmatically error [message #1695506 is a reply to message #1695422] |
Fri, 15 May 2015 12:29 |
|
Ok, turns out the KDM metamodel is fragmented over many EPackages, without a single top-level Resource that references all other EPackage Resources. The different KDM EPackages are all extensions of some other EPackage, in that their EClasses inherit from an EClass defined in the extended EPackage.
The conceptual metamodel-model relationship assumed in ATL - and pretty much all of the MDE community - (https://wiki.eclipse.org/ATL/Concepts#Model_Transformation), whereby each model has exactly one metamodel(1), does not hold for EMF. In EMF, you can reference any EClass from all over the place from any model, so a model can actually conform to a collection of metamodels. ATL does not support specifying a collection of metamodels for a model, and - to compensate for this - ATL traverses any metamodel you specify to find all related metamodels. The KDM metamodel frustrates this approach by providing a loosely coupled set of open-ended metamodels, whereby there is no top-level metamodel (i.e. EPackage).
Now, your transformation does not reference the entire KDM metamodel, so picking the right EPackage still worked for me: the CodePackage.eINSTANCE.eResource() did it for me. If this approach does not work for you in the long run, you can define your own top-level metamodel, which defines a single EClass that inherits from one EClass in each EPackage you want to import. That way, you "help" the ATL metamodel traversal algorithm.
You made one other mistake: the transformation module you use is a refining mode transformation module. That means the IN and OUT model are actually one and the same in EMFTVM; they are collapsed to a single in/out model, named IN. I've attached the fixed project for reference.
(1) The statement "exactly one metamodel" does not have to refer to a single, physical metamodel file; the metamodel can be spread over multiple files, as long as it is a bounded collection of files. EMF allows an unbounded collection of metamodel files to be used. As a consequence, a model transformation tool may not be able to anticipate all of the metaclasses an input EMF model uses, as new metaclasses may be loaded with the model.
Cheers,
Dennis
|
|
| | | | |
Goto Forum:
Current Time: Fri Sep 20 20:12:15 GMT 2024
Powered by FUDForum. Page generated in 0.05664 seconds
|