Generating code with Xtend and Xtext triggered from the Eclipse context menu

Aus SDQ-Wiki

This page explains how you can generate code from Ecore-based models using the Xtend language and the Xtext generator infrastructure. The important difference to usual code generation with Xtext is that the generation is triggered from the navigator context menu of Eclipse.

Why Xtext's Generator Infrastructure?

With the interfaces for generators, generator modules, and file system access the Xtext API makes it very convenient to generate Code for a given EMF Resource. You only have to specify which content you want to generate and the URIs of the files that contain should contain it.

Why not a normal Xtext project?

If you generate code for an Ecore metamodel that was not created with Xtext, then a normal Xtext project brings a lot of code an functionality that you do not need. If you do not want to trigger your generator each time a file of an Xtext-based DSL is saved but only when a specific command is used, then you do not need all the code of an Xtext project but only the part that eases the handling of input resources and output files.

Why sdq.commons.ecore2txt?

With this very small plug-in project we tried to give you only the code that is needed every time you want to generate any text files from Ecore-based models triggered by a context menu entry. And nothing more.

How to use it?

  • Check out and import the commons.ecore2txt plug-in project from svn (user:anonymous, password:anonymous).
  • Create a new plug-in project for your generator.
  • Create a generator that extends the IGenerator interface.
  • Create a generator module that extends AbstractEcore2TxtGeneratorModule and provides the getLanguageName and getFileExtensions methods.
  • Create a handler that extends AbstractEcore2TxtHandler and provides the executeEcore2TxtGenerator method.
    • You can easily implement this method by calling Ecore2TxtUtil.generateFromSelectedFilesInFolder(files,new YourOwnGeneratorModule(),new YourOwnGenerator(),"yourGenerationTargetFolderName")
  • Let your generator plug-in provide the following extensions
<extension
 point="org.eclipse.ui.commands">
<command
    defaultHandler="tld.domain.yourhandler"
    id="tld.domain.yourcodegencommand"
    name="Create Your Code">
</command>
</extension>
<extension
 point="org.eclipse.ui.menus">
<menuContribution
    allPopups="false"
    locationURI="popup:org.eclipse.ui.popup.any?after=additions">
 <menu
       id="yourmenu"
       label="Your Submenu label">
    <command
	  commandId="tld.domain.yourcodegencommand"
	  label="Create Your Code"
	  style="push"
	  tooltip="Create Code that ...">
    </command>
    <visibleWhen
	  checkEnabled="false">
       <with
	     variable="activeMenuSelection">
	  <iterate>
	  <adapt type="org.eclipse.core.resources.IResource">
      <or>
	 <test
	       property="org.eclipse.core.resources.name"
	       value="*.yourFileExt1">
	 </test>
	 <test
	       property="org.eclipse.core.resources.name"
	       value="*.yourFileExt2">
	 </test>
      </or>
	  </adapt>
	  </iterate>
       </with>
    </visibleWhen>
 </menu>
</menuContribution>
</extension>

A more detailed but also more complex tutorial that was used to build the ecore2txt plug-in was written by Christian Dietrich

What to copy and adapt?

YourGenerator:

import org.eclipse.emf.ecore.resource.Resource
import org.eclipse.xtext.generator.IFileSystemAccess
import org.eclipse.xtext.generator.IGenerator

class YourGenerator implements IGenerator {
	
      override doGenerate(Resource input, IFileSystemAccess fsa) {
		      val fileURI = ...
		      val contents = yourContentGeneration(input)
		      fsa.generateFile(fileURI, contents)
      }
	
}

YourGeneratorModule:

import edu.kit.ipd.sdq.commons.ecore2txt.generator.AbstractEcore2TxtGeneratorModule

class YourGeneratorModule extends AbstractEcore2TxtGeneratorModule {
	
	override protected String getLanguageName() {
		...
	}

	override protected String getFileExtensions() {
		...
	}

}

YourGeneratorHandler:

import org.eclipse.core.resources.IFile;

import edu.kit.ipd.sdq.commons.ecore2txt.handler.AbstractEcore2TxtHandler;
import edu.kit.ipd.sdq.commons.ecore2txt.util.Ecore2TxtUtil;
import YourGenerator;
import YourModule;

public class YourGeneratorHandler extends AbstractEcore2TxtHandler {

	@Override
	public void executeEcore2TxtGenerator(Iterable<IFile> files) {
		Ecore2TxtUtil.generateFromSelectedFilesInFolder(files,new YourGeneratorModule(),new YourGenerator(),"src-gen");
	}
}