Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » Model-Transformation: How to resolve custom generated Proxy-Objects.(Crossreference resolution in custom generated model)
Model-Transformation: How to resolve custom generated Proxy-Objects. [message #1832256] Mon, 14 September 2020 11:37 Go to next message
Jan Hermes is currently offline Jan HermesFriend
Messages: 27
Registered: September 2020
Junior Member
Hello Xtext-Experts,

I'm currently developing a language where I want to transform the generated AST-Model,
further called src-model,
into another AST-Model (defined and generated via emf-modelling tools),
called dst-model below.

After that I want to compile the transformed Model (dst-model) into the target-language.

Current state

Currently I successfully parse the source-model language and the generator gets called (the usual xtext-procedure).

After that I iterate through the AST of the Resource to be generated.
I transform every EObject from the src-model into the desired EObject
of the dst-model.

The generator then compiles the dst-model into a desired textual representation.

The only problem I encounter is, that while transforming the src-model I sometimes want
to generate ProxyObjects for the dst-model.
But I do not know how to correctly define the ProxyObjects, so that they later can be resolved
by e.g. EcoreUtil2.resolveAll.

Minimal Working Example

The example below does not have any real functionality or reason to exist,
it is just as simple as possible.

A minimal src-model-grammar

SrcSpecification:
    elements+=SrcElement*

SrcElement:
    SrcDeclaration | SrcReference

SrcDeclaration:
    "decl" name=ID

SrcReference:
    "ref" ref=[SrcDeclaration]


A minimal dst-model-grammar

DstSpecification:
    elements+=DstElement*

DstElement:
    DstDeclaration | DstReference

DstDeclaration:
    "decl" name=ID

DstReference:
    "ref" ref=[DstDeclaration]


mwe2-example only showing the additional configuration for the dst-model

// ...
Workflow {

    component = XtextGenerator {
        // ...
        // the usual workflow configurations for an xtext-language
        // ...

        language = XtextGeneratorLanguage {
			name = "org.example.mydsl.DstModel"	
			fileExtensions = "dstmodel"
			
			fragment = ecore.EMFGeneratorFragment2 {}
			fragment = resourceFactory.ResourceFactoryFragment2 {}
		}
    }
}


A singleton ResourceSet Provider for the dst-model

@singleton
class ResourceSetCreator {

    @Inject IResourceFactory resourceFactory
    @Inject IResourceServiceProvider serviceProvider 
    @Inject XtextResourceSet resourceSet

    def void registerExtension(String ext) {
		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(ext, resourceFactory)
		IResourceServiceProvider.Registry.INSTANCE.getExtensionToFactoryMap().put(ext, serviceProvider)
    }

    def Resource createResource(URI uri) {
        return resourceSet.createResource(uri)
    }

    def void resolve() {
        EcoreUtil2.resolveAll(resourceSet)
    }
}


The generator with proxy generation and the try to resolve them

//...

@Inject extension IQualifiedNameProvider 
@Inject ResourceSetCreator resourceSetCreator

override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {

    resourceSetCreator.registerExtension("dstmodel")

    val generatedResources = newArrayList()

    for (srcSpec: resource.contents.filter(SrcSpecification)) {

        val dstResource = resourceSetCreator.createResource(srcSpec.fullyQualifiedName.toString("/") + ".dstmodel")

        val transformedSpec = transformSrcSpecification(srcSpec)

        dstResource.contents.add(transformedSpec)

        generatedResources+=dstResource

    }

    resourceSetCreator.resolve()
}

def DstSpecification transformSrcSpecification(SrcSpecification srcSpec) {

    for (elem: srcSpec.elements) {

        switch(elem) {
            SrcDeclaration: transformSrcDeclaration(elem)
            SrcReference: transformSrcReference(elem)
        }
    }
}

def DstDeclaration transformSrcDeclaration(SrcDeclaration decl) {
    FACTORY.createDstDeclaration => [
        name = decl.name
    ]
}

def DstReference transformSrcReference(SrcReference ref) {

    val proxy = EcoreUtil2.create(FACTORY.createDstDeclaration.eClass) as InternalEObject
    proxy.eSetProxyURI(URI.createURI(ref.fullyQualifiedName.toString(".")))

    FACTORY.createDstReference => [
        ref = proxy as DstDeclaration
    ]

}

// ...



Actual Question

So the code above tries to build the dst-model from the src-model while creating proxy-objects for
model-elements that are not directly accessable at the time of creation.

Afterwards I wanted to leverage the resolve method of the EcoreUtil for the resolution of those proxy-objects
to its actual elements in the model (if they exist)

So in the end there are some question for this approach:


  1. How do I specifiy the Proxy Objects, Resource URIs and Object Uris correctly?
  2. Is this even possible with the standard crossreference resolution mechanism or do I need an actual parsable input?
Re: Model-Transformation: How to resolve custom generated Proxy-Objects. [message #1832272 is a reply to message #1832256] Tue, 15 September 2020 04:50 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

If you really want to generate proxy objects, see how the XML loader creates them.

However during many years usage of EMF I have not found that creating EMF-style proxy objects was helpful for model transformation. If nothing else it doubles object creation and confuses human debuggers.

Perhaps your M2M is too ambitious. Rather than go direct from Start2Finish, you may find it better to go Start2Intermediate2Finish with first class intermediate models representing intermediate analyses. You may even find that a longer chain enables you to address one concern at a time.

See https://www.sciencedirect.com/science/article/pii/S1571066105001350/pdf?md5=e7efab9f5c1bd35dff13575ab1d3e46d&pid=1-s2.0-S1571066105001350-main.pdf

Regards

Ed Willink

[Updated on: Tue, 15 September 2020 04:50]

Report message to a moderator

Re: Model-Transformation: How to resolve custom generated Proxy-Objects. [message #1832273 is a reply to message #1832272] Tue, 15 September 2020 06:41 Go to previous messageGo to next message
Ed Merks is currently offline Ed MerksFriend
Messages: 33136
Registered: July 2009
Senior Member
So specifically the issue is in transformSrcReference where you of course want a reference that resolves to the correct dst declaration. Generally a URI that will resolve to a given EObject is created via org.eclipse.emf.ecore.util.EcoreUtil.getURI(EObject). If you look at that implementation you can see that it generally includes the URI of the resource, org.eclipse.emf.ecore.resource.Resource.getURI(), along with a fragment computed by the resource itself, org.eclipse.emf.ecore.resource.Resource.getURIFragment(EObject). In your code you've created a URI without a fragment and that cannot resolve to anything but a resource via org.eclipse.emf.ecore.resource.ResourceSet.getResource(URI, boolean), i.e., org.eclipse.emf.ecore.resource.ResourceSet.getEObject(URI, boolean) can only find an EObject if there is a fragment in the URI. If each transformed object ends up in its own resource (which appears to be how you've written it), then likely the fragment '/' will work properly to select EObject at index 0 of that resource's contents. But, I wonder that you shouldn't be getting the fully qualified name of the ref's ref rather than of the ref itself.

A completely alternative approach is to implement your transformation maintain a map from src-thing to dst-thing such that each transform* method either creates the dst-thing corresponding to the src-thing, or returns the already-created dst-thing corresponding to that src-thing. Then you could call transformSrcDeclaration from transformSrcReference to find-or-create the dst-declaration. Note that very simple one-to-one transformations can be implemented by specializing org.eclipse.emf.ecore.util.EcoreUtil.Copier and then specializing org.eclipse.emf.ecore.util.EcoreUtil.Copier.getTarget(EClass) and org.eclipse.emf.ecore.util.EcoreUtil.Copier.getTarget(EStructuralFeature). Then org.eclipse.emf.ecore.util.EcoreUtil.Copier.copyReferences() is called at the end to hook up all the cross references after the containment structure has been copied...


Ed Merks
Professional Support: https://www.macromodeling.com/
Re: Model-Transformation: How to resolve custom generated Proxy-Objects. [message #1832501 is a reply to message #1832273] Sat, 19 September 2020 05:55 Go to previous message
Jan Hermes is currently offline Jan HermesFriend
Messages: 27
Registered: September 2020
Junior Member
Hello,

Thanks a lot for your input!

@Ed Merks
Yes I understand the uri problem and that I did not specify a correct fragment for the uri. In the end I also tried out a specific URIFragmentProvider that created uris like Fully Qualified Names not via "element.0..." etc.. But I recognized that I want to follow a completely different approach. instead of creating the model with proxies (explained below after @Ed Willink). Your approach with the direct Copier is a great additional info and I will definitely look into that. But in the end the two real models are pretty different and the transformation is not trivial enough for that I guess.

@Ed Willink
Your note about that the creation of proxies is not so nice for human debuggers also got me thinking. And the main thing also was to ask, what are the proxies for in the first place when xtext usses them for corssreference translation? And essentially they are used for resolving references AFTER the whole model is parsed. So i can parse all and then resolve all objects tht are references when the whole model is parsed... so if the model is valid all references are resolved.

This also means when I do my model transformation when the compiler is started (and when the model is validated) all src-model references are allready resolved correctly. So for the model I dont need to create proxy objects but I can always generated the references objects on demand and cache them for later so I dont generated them multiple times. So I ended pu to have a transformater that always directly transforms all references into the desired dst-model parts and caches those references-object-creations for later when the real object wants to be created.

So all in all thanks a lot for the help, and at the moment the approach above works perfectly fine.
Previous Topic:Xtext Build and Indexing taking more time
Next Topic:Language Server Project with implicit Environment-Resources
Goto Forum:
  


Current Time: Thu Apr 18 23:23:10 GMT 2024

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

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

Back to the top