Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » How to generate a factory?
How to generate a factory? [message #1467654] Mon, 10 November 2014 07:39 Go to next message
Markus Duft is currently offline Markus DuftFriend
Messages: 148
Registered: February 2013
Senior Member
Hey,

I have a set of DSL files that contain various model elements. I'm using IGenerator to generate Java Source code out of them.

Now I need a single factory some/most of those elements. How would I go for generating a factory that has all the required elements in there (also WRT the new paralllel generator mechanism)?

I thought about leveraging JDTs model and keeping a model of the factory in memory and manipulate it in a thread save way, but how to deal with removal of elements then? I'd have to keep track of elements per resource as thats the granularity I get in doGenerate...

Another approach would be to have a generator that builds the complete factory per plugin from the index as soon as the first resource for that bundle is encountered, and does nothing for the remaining resources. However, from the code I see that the IGenerator is only instanciated once, right? So I have no idea when to actually re-generate the factory and when not. I could only regenerate the factory always, which would be quite expensive.... What I'd need here would be a hook/method that is called once whenever a generator run (top level) starts, before the first resource is fed to doGenerate or something like that...

Any Ideas on this?
Thanks in advance...
Re: How to generate a factory? [message #1467668 is a reply to message #1467654] Mon, 10 November 2014 07:51 Go to previous messageGo to next message
Karsten Thoms is currently offline Karsten ThomsFriend
Messages: 596
Registered: July 2009
Location: Dortmund, Germany
Senior Member

Hi Markus,

There is Bug#351903 pending which will solve that issue for the future.
I have described the second approach you mention in this blog post:
https://kthoms.wordpress.com/2011/07/12/xtend-generating-from-multiple-input-models/

And right, it is quite expensive. However, it works for me. I am using this in several projects until there is better support by the framework.

HTH,
~Karsten


Need professional support for Xtext, Xpand, EMF?
Go to: http://xtext.itemis.com
Twitter : @kthoms
Blog : www.karsten-thoms.de
Re: How to generate a factory? [message #1467673 is a reply to message #1467668] Mon, 10 November 2014 07:58 Go to previous messageGo to next message
Markus Duft is currently offline Markus DuftFriend
Messages: 148
Registered: February 2013
Senior Member
Thanks, I'll try that one Smile
Re: How to generate a factory? [message #1468908 is a reply to message #1467673] Tue, 11 November 2014 06:27 Go to previous messageGo to next message
Markus Duft is currently offline Markus DuftFriend
Messages: 148
Registered: February 2013
Senior Member
Hey,

Thanks a lot for the starting point Smile I did something quite similar, but a little different...

1) I use BuilderParticipant as base classe, will use ParallelBuilderParticipant as soon as we're on 2.7.2. The 2.7.2 API is also a little bit nicer in that I can determine deletions also. This seems to be impossible with 2.6.0 AFAICT from the BuilderParticipant API. But thats not a real tragedy, in the (for us) rare case of a deletion one needs to do a clean build, et voila Smile
2) I implemented a "slim" mode, which loads resources from the current bundle, but not it's dependencies. For some use cases (like my "I want to generate a factory for some elements", the information without resolved cross references might already be enough Smile This speeds up the resource loading from around 5000ms to 200ms. As long as it's sufficient, I'll go with that.

Heres the code I came up with, just in case you find that interesting Smile

/**
 * Allows generation of code from multiple resources in the most efficient way that is possible.
 */
public interface IBundleModelGenerator {

    /**
     * @return <code>true</code> if the builder should only load the resources contained in the
     *         context bundle directly, without dependencies (there will be unresolved proxies!),
     *         <code>false</code> if the contents of visible bundles should be loaded also.
     */
    public boolean isSlim();

    /**
     * @return the file extension of model files, used to find resources.
     */
    public String getFileExtension();

    /**
     * Generates code out of multiple resources within a bundle. Depending on the implementation of
     * {@link #isSlim()}, the passed {@link ResourceSet} will contain either only resources from the
     * bundle in context, or from all visible bundles also.
     * 
     * @param context
     *            the build context to allow determination of the bundle in context.
     * @param resources
     *            the rources loaded for this generator.
     * @param fsa
     *            the {@link IFileSystemAccess} to generate files through
     */
    public void doGenerate(IBuildContext context, ResourceSet resources, IFileSystemAccess fsa);
}


and the BuilderParticipant:

class BundleModelBuilderParticipant extends BuilderParticipant {

	@Inject private ResourceDescriptionsProvider descriptionsProvider
	@Inject private IContainer.Manager containerManager
	@Inject(optional=true) private IBundleModelGenerator bundleModelGenerator
	
	private val modelGeneratorLock = new AtomicBoolean

	override build(IBuildContext context, IProgressMonitor monitor) throws CoreException {
		modelGeneratorLock.set(true)
		super.build(context, monitor)
	}
	
	override protected handleChangedContents(Delta delta, IBuildContext context, EclipseResourceFileSystemAccess2 fsa) throws CoreException {
		super.handleChangedContents(delta, context, fsa)
		
		if (bundleModelGenerator != null && modelGeneratorLock.compareAndSet(true, false)) {
			val start = System.currentTimeMillis
			val set = context.resourceSet
			val resources = findModelResources(context.builtProject)
			System.err.println("finding resources took " + (System.currentTimeMillis - start))
			if (bundleModelGenerator.slim) {
				for (r : resources) {
					set.getResource(getResourcePlatformURI(r), true)
				}
			} else {
				// obtain the containers by querying for any of the resources in the bundle
				val index = descriptionsProvider.createResourceDescriptions
				val anyDesc = index.getResourceDescription(getResourcePlatformURI(resources.get(0)))
				val containers = containerManager.getVisibleContainers(anyDesc, index)
				
				for(c : containers) {
					for(rd : c.resourceDescriptions) {
						set.getResource(rd.URI, true)
					}
				}
			}
			System.err.println("loading resources took " + (System.currentTimeMillis - start))
			
			bundleModelGenerator.doGenerate(context, set, fsa)
			System.err.println("bundle model generator took " + (System.currentTimeMillis - start) + "ms")
		}
	}

	/**
	 * Retrieves the platform:/ URI for the given resource.
	 */
	private def getResourcePlatformURI(IResource r) {
		URI.createPlatformResourceURI(r.getProject().getName() + "/" + r.getProjectRelativePath().toPortableString(),
			true)
	}

	/**
	 * Find model resources in the given project. This yields only resources directly contained in the project.
	 */
	private def findModelResources(IProject project) {
		val files = newArrayList()

		project.accept(
			[ resource |
				if (resource.getFileExtension() != null &&
					resource.getFileExtension().equalsIgnoreCase(bundleModelGenerator.fileExtension)) {
					files.add(resource);
				}
				return true;
			]);

		files
	}
}


Then I just bound the generator implementation in the runtime module, and the builder participant in the UI module. Works like a charm - for modifications at least Wink

P.S.: of course the System.err.println should be removed Very Happy

Cheers,
Markus
Re: How to generate a factory? [message #1781201 is a reply to message #1468908] Fri, 02 February 2018 16:49 Go to previous messageGo to next message
Amit Yadav is currently offline Amit YadavFriend
Messages: 28
Registered: June 2017
Junior Member
Hello,

I am trying to solve the same problem, except in my case this needs to be done in standalone mode only, so its going to be always a full build. Any suggestions on how I can achieve that ?

Thanks,

Amit
Re: How to generate a factory? [message #1781211 is a reply to message #1781201] Fri, 02 February 2018 20:05 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 11958
Registered: July 2009
Senior Member
what do you do right now? how do you read models and call generator

Need professional support for Xtext, Xpand, EMF?
Go to: https://xtext.itemis.com
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: How to generate a factory? [message #1781215 is a reply to message #1781211] Fri, 02 February 2018 22:47 Go to previous messageGo to next message
Amit Yadav is currently offline Amit YadavFriend
Messages: 28
Registered: June 2017
Junior Member
Right now, I am using XBase and using JvmModelInferrer to infer the code. I wrote a a small compiler (based on the generateXtendMain code). The compiler

1. Loads a resource (via a file URI) in a resource set.
2. Call the validator on the resource.
3. Call the generator on the resource.

I need to modify this now to work with multiple resources in the resource set and then generating a factory which needs a inferred jvm type from all resources.
Re: How to generate a factory? [message #1781218 is a reply to message #1781215] Sat, 03 February 2018 08:35 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 11958
Registered: July 2009
Senior Member
Simply call a different thing with the resourceset ?

Need professional support for Xtext, Xpand, EMF?
Go to: https://xtext.itemis.com
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: How to generate a factory? [message #1781300 is a reply to message #1781218] Mon, 05 February 2018 20:02 Go to previous messageGo to next message
Amit Yadav is currently offline Amit YadavFriend
Messages: 28
Registered: June 2017
Junior Member
That would work. However, Will doing the following in the different thing suffice
1. Run an inferrer in the resource set.
2. Add the generated JvmGenericType(s) to appropriate resource(s).

is there anything else which should/needs to be done (before calling the generator on each resource in the resource set). ?
Re: How to generate a factory? [message #1781302 is a reply to message #1781300] Mon, 05 February 2018 20:11 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 11958
Registered: July 2009
Senior Member
I don't understand.
The inferrer is called on resource load, not on generation


Need professional support for Xtext, Xpand, EMF?
Go to: https://xtext.itemis.com
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: How to generate a factory? [message #1781306 is a reply to message #1781302] Mon, 05 February 2018 21:15 Go to previous messageGo to next message
Amit Yadav is currently offline Amit YadavFriend
Messages: 28
Registered: June 2017
Junior Member
Here is what I am doing right now (which seems to work)

1. Loads all the resources (via a file URI) in a resource set.
2. Call the validator on each resource (This will in turn call the inferrer and add the inferred types to the resource's content)
3. Call a custom inferrer on the resource set (This will inferrer any types across the resources and add to appropriate resource's content).
4. Call the generator on each of the resource in the resource set.

I am wondering if step 3 requires more work then simply inferring a type and adding it to resource's content.

Re: How to generate a factory? [message #1781326 is a reply to message #1781306] Tue, 06 February 2018 06:43 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 11958
Registered: July 2009
Senior Member
in dont know how your 3 differs from the default mechanism

Need professional support for Xtext, Xpand, EMF?
Go to: https://xtext.itemis.com
Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:Xtend templates execution : unable to print return value of a method when used in forEach
Next Topic:Negative numbers in Xtext Arithmetic Sample
Goto Forum:
  


Current Time: Tue May 22 02:45:55 GMT 2018

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

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

Back to the top