Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » ATL » Calling EMFTVM programmatically error
Calling EMFTVM programmatically error [message #1695017] Mon, 11 May 2015 12:23 Go to next message
Rafael Durelli is currently offline Rafael DurelliFriend
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 Go to previous messageGo to next message
Dennis Wagelaar is currently offline Dennis WagelaarFriend
Messages: 350
Registered: September 2012
Location: Belgium
Senior Member

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 #1695155 is a reply to message #1695124] Tue, 12 May 2015 11:21 Go to previous messageGo to next message
Rafael Durelli is currently offline Rafael DurelliFriend
Messages: 72
Registered: September 2012
Member
Hello Dennis can you please help me out in here... I'm not sure how to fix the remarks you gave me. What exactly should i do? THanks in advance;


Dennis Wagelaar wrote on 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

Re: Calling EMFTVM programmatically error [message #1695223 is a reply to message #1695155] Tue, 12 May 2015 19:49 Go to previous messageGo to next message
Dennis Wagelaar is currently offline Dennis WagelaarFriend
Messages: 350
Registered: September 2012
Location: Belgium
Senior Member

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 #1695292 is a reply to message #1695223] Wed, 13 May 2015 11:32 Go to previous messageGo to next message
Rafael Durelli is currently offline Rafael DurelliFriend
Messages: 72
Registered: September 2012
Member
Sorry Dennis but it still noes not work. The output is the same Sad.
Re: Calling EMFTVM programmatically error [message #1695326 is a reply to message #1695292] Wed, 13 May 2015 13:30 Go to previous messageGo to next message
Dennis Wagelaar is currently offline Dennis WagelaarFriend
Messages: 350
Registered: September 2012
Location: Belgium
Senior Member

Ok, can you zip your Eclipse project and attach it? That way we can try to reproduce the problem.
If you cannot attach to the forum, just open a new Bugzilla issue and attach it there (https://bugs.eclipse.org/bugs/enter_bug.cgi?product=MMT.ATL).


Cheers,
Dennis
Re: Calling EMFTVM programmatically error [message #1695422 is a reply to message #1695326] Thu, 14 May 2015 13:02 Go to previous messageGo to next message
Rafael Durelli is currently offline Rafael DurelliFriend
Messages: 72
Registered: September 2012
Member
Dennis, I'm attaching the source code herein. THanks in advance. Have a nice day.
  • Attachment: send.zip
    (Size: 3.25MB, Downloaded 86 times)
Re: Calling EMFTVM programmatically error [message #1695506 is a reply to message #1695422] Fri, 15 May 2015 12:29 Go to previous messageGo to next message
Dennis Wagelaar is currently offline Dennis WagelaarFriend
Messages: 350
Registered: September 2012
Location: Belgium
Senior Member

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
Re: Calling EMFTVM programmatically error [message #1696156 is a reply to message #1695506] Fri, 22 May 2015 12:43 Go to previous message
Rafael Durelli is currently offline Rafael DurelliFriend
Messages: 72
Registered: September 2012
Member
Thanks Dannis it works.
Previous Topic:Create a copy of an output-pattern-element
Next Topic:Generating random values, etc.
Goto Forum:
  


Current Time: Fri Sep 22 17:17:24 GMT 2017

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

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