Consider the basic ATL transformation Families2Persons, running it through EMFTVM and getting the traces as explained in the docs.

-- @atlcompiler emftvm
-- @path Families=/Test/Families.ecore
-- @path Persons=/Test/Persons.ecore

module Families2Persons;

create OUT: Persons, trace: Trace from IN: Families;

rule Member2Male {
    from
        s: Families!Member (not s.isFemale())
    to
        t: Persons!Male (
            fullName <- s.firstName + ' ' + s.familyName
        )
}

rule Member2Female {
    from
        s: Families!Member (s.isFemale())
    to
        t: Persons!Female (
            fullName <- s.firstName + ' ' + s.familyName
        )
}

I omitted the helper functions to save space, but I didn't change them compared with the tutorial example

When I ran the transformation using my Eclipse environment, everything worked fine and I got the result model and the traces as expected. Below is a snippet of the traces.xmi generated after running it.

   <links>
      <sourceElements name="s" defaultFor="/">
        <object href="../sample-Families.xmi#/0/@father"/>
      </sourceElements>
      <targetElements name="t">
        <object href="../person-emftvm.xmi#/0"/>
      </targetElements>
    </links>

Trying to run the same transformation programmatically (also adapting the Java code from the docs), I got the same model output, but my traces model includes the absolute path instead of the relative path like the previous example. Snippets below:

Java code:

public class RunTestTransformation {

    public static String here = new File(".").getAbsolutePath();

    public static URI resourceURI(String relativePath) {
        return URI.createFileURI(here + relativePath);
    }

    public static void main(String[] args) throws IOException {

        Map<String, Object> map = Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap();
        map.put("xmi", new XMIResourceFactoryImpl());
        map.put("ecore", new EcoreResourceFactoryImpl());
        map.put("emftvm", new EMFTVMResourceFactoryImpl());

        ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
        ResourceSet rs = new ResourceSetImpl();

        // Register the metamodels into resource set
        EPackage FamiliesPkg = (EPackage) rs.getResource(resourceURI("/../Test/Families.ecore"), true).getContents()
                .get(0);
        EPackage.Registry.INSTANCE.put(FamiliesPkg.getNsURI(), FamiliesPkg);
        EPackage PersonsPkg = (EPackage) rs.getResource(resourceURI("/../Test/Persons.ecore"), true).getContents()
                .get(0);
        EPackage.Registry.INSTANCE.put(PersonsPkg.getNsURI(), PersonsPkg);

        // Load metamodels into execenv
        Metamodel familiesMetaModel = EmftvmFactory.eINSTANCE.createMetamodel();
        familiesMetaModel.setResource(rs.getResource(resourceURI("/../Test/Families.ecore"), true));
        env.registerMetaModel("Families", familiesMetaModel);

        Metamodel personsMetaModel = EmftvmFactory.eINSTANCE.createMetamodel();
        personsMetaModel.setResource(rs.getResource(resourceURI("/../Test/Persons.ecore"), true));
        env.registerMetaModel("Persons", personsMetaModel);

        String relativeInputPath = "/../Test/sample-Families.xmi";
        String relativeTracePath = "/../Test/traces.xmi";
        String relativeOutputPath = "/../Test/persons.xmi";

        // Load models
        URI inputUri = resourceURI(relativeInputPath);
        Model inModel = EmftvmFactory.eINSTANCE.createModel();
        inModel.setResource(rs.getResource(inputUri, true));
        env.registerInputModel("IN", inModel);

        URI uriTrace = resourceURI(relativeTracePath);
        Model traceOutModel = EmftvmFactory.eINSTANCE.createModel();
        traceOutModel.setResource(rs.createResource(uriTrace));
        env.registerOutputModel("trace", traceOutModel);

        URI uriOut = resourceURI(relativeOutputPath);
        Model outModel = EmftvmFactory.eINSTANCE.createModel();
        outModel.setResource(rs.createResource(uriOut));
        env.registerOutputModel("OUT", outModel);

        // Load and run module
        ModuleResolver mr = new DefaultModuleResolver("./../Test/emftvm/", rs);
        TimingData td = new TimingData();
        env.loadModule(mr, "Families2Persons");
        td.finishLoading();
        env.run(td);
        td.finish();

        // Save models
        inModel.getResource().save(Collections.emptyMap());
        traceOutModel.getResource().save(Collections.emptyMap());
        outModel.getResource().save(Collections.emptyMap());
    }
}

Output trace excerpt:

   <links>
      <sourceElements name="s" defaultFor="/">
        <object href="file:/C:/Users/XXXX/./../Test/sample-Families.xmi#/0/@father"/>
      </sourceElements>
      <targetElements name="t">
        <object href="file:/C:/Users/XXXX/./../Test/persons.xmi#/0"/>
      </targetElements>
    </links>

How can I get the same result for traces both running through Eclipse and programmatically? I can understand that the problem is that my Eclipse environment knows about my workspace, but I don't know how to configure my Java code to behave similarly.

I've tried

  1. Change createFileURI() by createURI() -> Compilation error
  2. Different XMLResource options in the save() method -> Not effective
  3. Pass direct my "relativepath" to createFileURI() instead of appending it to the current Java file location (see method resourceURI() in the code) -> File not found
1

There are 1 best solutions below

2
On BEST ANSWER

I guess the issue is with how you are loading your models programmatically. Currently you are using file URIs. I guess ATL being installed in your current running Eclipse, works mostly with 'platform:/resource' URIs. And probably when serializing the trace model, EMF identifies that both Resources are not far from each other and thus prefers serializing with relative URIs.

So I think the fix depends on whether your code is supposed to be a standalone Java application or embedded in Eclipse. If the latter, then simply loading models with 'platform:/resource' might maybe work. Of course you will have to find some way to have your files into your running instance workspace location. If the former, I think you maybe have to play with the org.eclipse.emf.ecore.resource.URIConverter of your ResourceSet