Using Xpand in Your Eclipse Wizards
At ESE, I had a nice chat with Chris (actually, I had a lot of nice chats with a lot of nice people - it was quite a challenge to attend any of the sessions), who told me that he was looking into template engines. I leave it up to you to make any assumptions on why he's interested in template engines. I happen to know at least three template engines: Velocity (which I had the joy of using in my active days at AndroMDA.org), the template, erhm, ... mechanism being used in PDE (I once fixed a bug which had been caused by this engine) and - you might have guessed it - Xpand (which I am a committer on).
So, I gave a short demo of Xtext and Xpand to show Chris how easy it is to create (model-aware) code generation templates. Xpand comes with a nice editor which makes template editing a joy - it features code highlighting, hyperlink navigation, model-awareness and other editor goodness.
Instead of letting only Chris know how that works, here's a short guide on how to write your own Xpand template and use it in a wizard. To make the example more realistic, I chose to implement a wizard that creates an Ant build.xml file for a simple project (something which is missing in Eclipse, AFAIK). So, here we go.
Prerequisites:
- Eclipse 3.5M3 (3.4 might also do)
- EMF 2.5.0M3
- EMF Compare 0.8.1
- MWE 0.7.0M3
- Xpand 0.7.0M3
How to do it
- Download and install the prerequisites.
- Create a new plug-in project named "de.peterfriese.antwizard"
- Add a New File Wizard to the project. I used the Custom plug-in Wizard to get me started.
- Brush up the wizard page and add some fields for project name, source folder and binary folder.
- We want to transfer the values entered in this wizard into our template, so we need to create an Ecore model that describes our data model.

- Add org.eclipse.emf and org.eclipse.emf.edit to the dependencies of you plug-in.
- Create a genmodel and let EMF generate the model code for you.
- Add code to your wizard that transfers the values from the input fields to your model. One might consider using databinding for doing this, I used a straight forward read'n'write approach for the time being:
public boolean performFinish() { final String containerName = page.getContainerName(); final String srcDirName = page.getSrcDirName(); final String binDirName = page.getBinDirName(); // ... } private BuildSpecification createModel(IProject project, String srcDirName, String binDirName) { BuildSpecification buildSpecification = BuildspecificationFactory.eINSTANCE.createBuildSpecification(); Project projectSpecification = BuildspecificationFactory.eINSTANCE.createProject(); projectSpecification.setName(project.getName()); projectSpecification.setBinaryFolder(binDirName); projectSpecification.setSourceFolder(srcDirName); buildSpecification.setProject(projectSpecification); return buildSpecification; } - Create an Xpand template de.peterfriese.antwizard/src/template/BuildTemplate.xpt:

In case you wonder how to get those funky characters: make sure us create this file using the Xpand editor - it has code assist (CTRL + space) for those characters. - Create an Xtend file de.peterfriese.antwizard/src/template/GeneratorExtensions.ext:

- Add org.eclipse.xpand, org.eclipse.xtend and org.eclipse.xtend.typesystem.emf to the depencies of your plug-in.
- Finally, we need to provide some code to invoke the generator:
private void generate(BuildSpecification buildSpec, IProgressMonitor monitor) throws CoreException { // get project root folder as absolute file system path IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IResource resource = root.findMember(new Path(buildSpec.getProject().getName())); String containerName = resource.getLocation().toPortableString(); // configure outlets OutputImpl output = new OutputImpl(); Outlet outlet = new Outlet(containerName); outlet.setOverwrite(true); output.addOutlet(outlet); // create execution context Map globalVarsMap = new HashMap(); XpandExecutionContextImpl execCtx = new XpandExecutionContextImpl(output, null, globalVarsMap, null, null); EmfRegistryMetaModel metamodel = new EmfRegistryMetaModel() { @Override protected EPackage[] allPackages() { return new EPackage[] { BuildspecificationPackage.eINSTANCE, EcorePackage.eINSTANCE }; } }; execCtx.registerMetaModel(metamodel); // generate XpandFacade facade = XpandFacade.create(execCtx); String templatePath = "template::BuildTemplate::main"; facade.evaluate(templatePath, buildSpec); // refresh the project to get external updates: resource.refreshLocal(IResource.DEPTH_INFINITE, monitor); }
That's it!
Taking it for a spin
- Launch a runtime workbench by selecting de.peterfriese.antwizard/META-INF/MANIFEST.MF and invoking Run As -> Eclipse Application
- Create a new Java project in the runtime workspace.
- Invoke your wizard by selecting File -> New -> Other... -> Ant -> Ant build file from existing project
- Enter the required information (project name, source folder, binariy folder)
- After clicking on finish, you should get a fresh Ant file for your project:

- Enjoy!
You can download the project here. Feedback and comments are welcome!
From http://www.peterfriese.de
Peter Friese is a software architect with itemis. He is a committer for the open source projects openArchitectureWare, Eclipse Modeling, FindBugs, and AndroMDA. As a software engineer and software architect, Peter has worked on a variety of industry projects in different domains such as banking, aerospace and transport. He is a regular speaker at various conferences and has authored a number of articles on topics like Eclipse, Spring, and model-driven software development. He can be contacted at peter.friese@itemis.de. Peter is a DZone MVB and is not an employee of DZone and has posted 13 posts at DZone.
- Login or register to post comments
- 2099 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)










Comments
Steffen Kobilke replied on Mon, 2009/04/06 - 11:23am