I'm trying to combine XText with EMF's ATL model to model transformation. I'm reading my DSL, dump it into EMF's XMI resource and put it into the ATL api: ATL does not give me any errors and runs correctly:
Number of instructions executed: 38
Whatever I do, my OutModel (palData) stays empty (null). If I take all the files from here (hdl.ecore, pal.ecore, hdl.xmi) and put them into the example ATL project, I get an output that is correct.
So is there any magic parameter that I need to throw onto the EMFVM launcher?
My code for triggering the ATL:
// create stuff
EMFModelFactory emfFactory = new EMFModelFactory();
XMIResourceFactoryImpl xmiFactory = new XMIResourceFactoryImpl();
EMFExtractor extractor = new EMFExtractor();
EMFInjector emfInjector = new EMFInjector();
ResourceSet resourceSet = new ResourceSetImpl();
// load model
EMFReferenceModel hdlMetaModel = (EMFReferenceModel) emfFactory.newReferenceModel();
emfInjector.inject(hdlMetaModel, resourceSet.getResource(URI.createFileURI("org.xtext.hal/model/generated/Hdl.ecore"), true));
EMFModel hdlData = (EMFModel) emfFactory.newModel(hdlMetaModel);
EMFReferenceModel palMetaModel = (EMFReferenceModel) emfFactory.newReferenceModel();
emfInjector.inject(palMetaModel, resourceSet.getResource(URI.createFileURI("org.xtext.hal/model/Pal.ecore"), true));
EMFModel palData = (EMFModel) emfFactory.newModel(palMetaModel);
palData.setIsTarget(true);
// load xtext content, convert to xmi
Resource xmiResource = xmiFactory.createResource(URI.createURI("org.xtext.hal/model/generated/Hdl.xmi"));
xmiResource.getContents().addAll(hdlModel.getContents());
emfInjector.inject(hdlData, xmiResource);
// ATL transformation
InputStream asm = new FileInputStream("org.xtext.hal/model/Pal.asm");
EMFVMLauncher launcher = new EMFVMLauncher();
HashMap<String,Object> options = new HashMap<String,Object>();
options.put("showSummary", "true");
options.put("step", "true");
launcher.initialize(Collections.<String, Object> emptyMap());
launcher.addInModel(hdlData, "IN", "hdl");
launcher.addOutModel(palData, "OUT", "pal");
launcher.launch(ILauncher.DEBUG_MODE, new NullProgressMonitor(), options, asm);
// get output
Resource t_palData = palData.getResource();
t_palData.setURI(URI.createURI("palData.xmi")); // Exception in thread "main" java.lang.NullPointerException
t_palData.save(null);
My is here ATL:
-- @path hdl=/org.xtext.hal/model/generated/Hdl.ecore
-- @path pal=/org.xtext.hal/model/Pal.ecore
module HDL2PAL;
create OUT : pal from IN : hdl;
rule Foobar
{
from
s : hdl!Model
to
t : pal!AddressSpace (
name <- s.name
)
}
HDL.ecore (input metamodel):
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="hdl" nsURI="http://www.xtext.org/hal/Hdl" nsPrefix="hdl">
<eClassifiers xsi:type="ecore:EClass" name="Model">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
</ecore:EPackage>
PAL.ecore (output metamodel):
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="pal" nsURI="http://www.xtext.org/hal/Pal" nsPrefix="pal">
<eClassifiers xsi:type="ecore:EClass" name="AddressSpace">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
</eClassifiers>
</ecore:EPackage>
Model data for the input:
<?xml version="1.0" encoding="ASCII"?>
<hdl:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:hdl="http://www.xtext.org/hal/Hdl" name="bar"/>
Output from the ATL example project:
<?xml version="1.0" encoding="ISO-8859-1"?>
<pal:AddressSpace xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:pal="http://www.xtext.org/hal/Pal" name="bar"/>
Output from the ATL assambler:
main:0 getasm
stack: HDL2PAL : ASMModule
locals: self=HDL2PAL : ASMModule
main:1 push OclParametrizedType
stack: HDL2PAL : ASMModule, 'OclParametrizedType'
locals: self=HDL2PAL : ASMModule
main:2 push #native
stack: HDL2PAL : ASMModule, 'OclParametrizedType', '#native'
locals: self=HDL2PAL : ASMModule
main:3 new
stack: HDL2PAL : ASMModule, <unnamed>(null)
locals: self=HDL2PAL : ASMModule
main:4 dup
stack: HDL2PAL : ASMModule, <unnamed>(null), <unnamed>(null)
locals: self=HDL2PAL : ASMModule
main:5 push Collection
stack: HDL2PAL : ASMModule, <unnamed>(null), <unnamed>(null), 'Collection'
locals: self=HDL2PAL : ASMModule
main:6 pcall J.setName(S):V
locals: self=HDL2PAL : ASMModule Calling <unnamed>(null).setName('Collection')
stack: HDL2PAL : ASMModule, Collection(null)
locals: self=HDL2PAL : ASMModule
main:7 dup
stack: HDL2PAL : ASMModule, Collection(null), Collection(null)
locals: self=HDL2PAL : ASMModule
main:8 push OclSimpleType
stack: HDL2PAL : ASMModule, Collection(null), Collection(null), 'OclSimpleType'
locals: self=HDL2PAL : ASMModule
main:9 push #native
stack: HDL2PAL : ASMModule, Collection(null), Collection(null), 'OclSimpleType', '#native'
locals: self=HDL2PAL : ASMModule
main:10 new
stack: HDL2PAL : ASMModule, Collection(null), Collection(null), <unnamed>
locals: self=HDL2PAL : ASMModule
main:11 dup
stack: HDL2PAL : ASMModule, Collection(null), Collection(null), <unnamed>, <unnamed>
locals: self=HDL2PAL : ASMModule
main:12 push OclAny
stack: HDL2PAL : ASMModule, Collection(null), Collection(null), <unnamed>, <unnamed>, 'OclAny'
locals: self=HDL2PAL : ASMModule
main:13 pcall J.setName(S):V
locals: self=HDL2PAL : ASMModule Calling <unnamed>.setName('OclAny')
stack: HDL2PAL : ASMModule, Collection(null), Collection(null), OclAny
locals: self=HDL2PAL : ASMModule
main:14 pcall J.setElementType(J):V
locals: self=HDL2PAL : ASMModule Calling Collection(null).setElementType(OclAny)
stack: HDL2PAL : ASMModule, Collection(OclAny)
locals: self=HDL2PAL : ASMModule
main:15 set col
stack:
locals: self=HDL2PAL : ASMModule
main:16 getasm
stack: HDL2PAL : ASMModule
locals: self=HDL2PAL : ASMModule
main:17 push TransientLinkSet
stack: HDL2PAL : ASMModule, 'TransientLinkSet'
locals: self=HDL2PAL : ASMModule
main:18 push #native
stack: HDL2PAL : ASMModule, 'TransientLinkSet', '#native'
locals: self=HDL2PAL : ASMModule
main:19 new
stack: HDL2PAL : ASMModule, TransientLinkSet {}
locals: self=HDL2PAL : ASMModule
main:20 set links
stack:
locals: self=HDL2PAL : ASMModule
main:21 getasm
stack: HDL2PAL : ASMModule
locals: self=HDL2PAL : ASMModule
main:22 pcall A.__matcher__():V
locals: self=HDL2PAL : ASMModule Calling HDL2PAL : ASMModule.__matcher__()
__matcher__:0 getasm
stack: HDL2PAL : ASMModule
locals: self=HDL2PAL : ASMModule
__matcher__:1 pcall A.__matchFoobar():V
locals: self=HDL2PAL : ASMModule Calling HDL2PAL : ASMModule.__matchFoobar()
__matchFoobar:0 push Model
stack: 'Model'
locals: self=HDL2PAL : ASMModule
__matchFoobar:1 push hdl
stack: 'Model', 'hdl'
locals: self=HDL2PAL : ASMModule
__matchFoobar:2 findme
stack: hdl!Model
locals: self=HDL2PAL : ASMModule
__matchFoobar:3 push IN
stack: hdl!Model, 'IN'
locals: self=HDL2PAL : ASMModule
__matchFoobar:4 call MMOF!Classifier;.allInstancesFrom(S):QJ
locals: self=HDL2PAL : ASMModule Calling hdl!Model.allInstancesFrom('IN')
stack: OrderedSet {}
locals: self=HDL2PAL : ASMModule
__matchFoobar:5 iterate
stack:
locals:
stack:
locals:
stack:
locals: self=HDL2PAL : ASMModule
main:23 getasm
stack: HDL2PAL : ASMModule
locals: self=HDL2PAL : ASMModule
main:24 pcall A.__exec__():V
locals: self=HDL2PAL : ASMModule Calling HDL2PAL : ASMModule.__exec__()
__exec__:0 getasm
stack: HDL2PAL : ASMModule
locals: self=HDL2PAL : ASMModule
__exec__:1 get links
stack: TransientLinkSet {}
locals: self=HDL2PAL : ASMModule
__exec__:2 push Foobar
stack: TransientLinkSet {}, 'Foobar'
locals: self=HDL2PAL : ASMModule
__exec__:3 call NTransientLinkSet;.getLinksByRule(S):QNTransientLink;
locals: self=HDL2PAL : ASMModule Calling TransientLinkSet {}.getLinksByRule('Foobar')
stack: []
locals: self=HDL2PAL : ASMModule
__exec__:4 iterate
stack:
locals:
stack:
locals:
You're loading the HDL metamodel from file after you've loaded your model:
EMFReferenceModel hdlMetaModel = (EMFReferenceModel) emfFactory.newReferenceModel(); emfInjector.inject(hdlMetaModel, resourceSet.getResource(URI.createFileURI("org.xtext.hal/model/generated/Hdl.ecore"), true));
The existing "hdlModel" will contain EObjects that link to other instances of EClass than those loaded by you into "hdlMetaModel". Hence, if ATL tries to determine all instances of "hdl!Model", it will not find anything: the real instances refer to another version of "hdl!Model". The solution is to obtain the pre-loaded version of the HDL metamodel as loaded by xText.
P.S. Most support discussion on ATL goes on at the ATL forum. You may want to continue the discussion there.