Acceleo/Getting Started 33

From Kompilatory
Jump to: navigation, search
Getting started banner.png

First Generator Module (Acceleo 3.3+)

Authors Laurent Goubet
            Laurent Delaigue
Contact laurent.goubet@obeo.fr
            laurent.delaigue@obeo.fr

Copyright 2008, 2011 Obeo.

Upgraded to Acceleo 3.3+ by Tomasz Babczyński
Contact tomasz.babczynski@pwr.edu.pl


Introduction

The aim of this tutorial is to get you started with Acceleo by helping you create your first generation module. For the purpose of this tutorial, we will focus on creating an Acceleo module that generates Java beans from a UML model. You will need an ".uml" model as the input of the soon created generator. You can create one thanks to the wizards and editor provided by the UML project. Alternatively you can create one using Obeo UMLDesigner. At least you can take the model provided in the UML to Java Acceleo example (File -> New -> Example -> Acceleo -> UML to Java).

Getting started uml model example.png

Use the Acceleo perspective

Using the Acceleo perspective will make things easier when working with Acceleo as it provides dedicated views and actions. Furthermore, being on that perspective will promote some menu items so that they are directly accessible instead of being nested within others.

You can switch to the Acceleo perspective by selecting the Window > Open Perspective > Other... menu and selecting Acceleo in the popup that appears then.

Acceleo-userguide-perspective-acceleo.png


Create an Acceleo Project

Acceleo Projects are meant to provide you with facilities to write your Acceleo modules. In order to create a new Acceleo project, use the menu item File > New > Acceleo Project.

Getting started new acceleo module project.png

Choose the name you want for your project (here, we'll go for the default org.eclipse.acceleo.module.sample), then click Next>.

Getting started new acceleo module project 1.png

This second wizard page allows you to initialize the project by creating one or several Acceleo module files.

  • Select the folder in which you want to create the new module file.
  • Fill in the module name (we'll leave it as generate in this example).
  • Select the metamodel from which your generation module will take its types (in this example, UML).
  • Finally, choose the metaclass that will be used to generate the file (in this example, Class). This can be modified later at any time directly in the module files.

Note: other options are available to initialize the new module with existing content. These will be discussed in detail later.

Getting started new acceleo module project 2.png

You can create more than one module file in this project by using the "Add" button on the left, we only need one in this example.

Clicking on finish will create the module file(s), and some files automatically generated from it (more on these below).

Getting started new acceleo module project result.png


The Acceleo editor

The Acceleo module editor provides the following features:

  • Syntax highlighting
  • Content assistant (ctrl + space)
  • Error detection
  • Quick fixes (ctrl + shift + 1)
  • Dynamic outline
  • Quick outline (ctrl + O)
  • Code folding
  • Open declaration (either with 'ctrl + left click' or 'F3' on selection)
  • Search references (ctrl + shift + G)
Getting started acceleo editor.png

For more information about the Acceleo syntax, please read the official OMG specification accessible from the official MTL Specification.


Generating java beans

We would now like to create a bean for each of the classes defined in our sample model. Here is the code for the module file:

 [comment encoding = UTF-8 /]
 [module generate('http://www.eclipse.org/uml2/5.0.0/UML')/]
 
 [template public generateElement(aClass : Class)] 
  [comment @main /]
 [file (aClass.name.concat('.java'), false)]
   public class [aClass.name.toUpperFirst()/] {
   [for (p: Property | aClass.attribute) separator('\n')]
     private [p.type.name/] [p.name/];
   [/for]
 
   [for (p: Property | aClass.attribute) separator('\n')]
     public [p.type.name/] get[p.name.toUpperFirst()/]() {
       return this.[p.name/];
     }
   [/for]
 
   [for (o: Operation | aClass.ownedOperation) separator('\n')]
     public [o.type.name/] [o.name/]() {
       // TODO should be implemented
     }
   [/for]
   }
 [/file]
 [/template]

As shown below, the content assistant provides choices from the UML metamodel:

Getting started acceleo editor example.png

You can now launch the generation of your Java beans using this generation module but you need an ".uml" model as the input. You can create one thanks to the wizards and editor provided by the UML project or you can take the one provided in the UML to Java Acceleo example (File -> New -> Example -> Acceleo -> UML to Java).

In order to do this, you will have to :

Right-click on the Acceleo module file (that is, the generate.mtl file) and select Run As > Launch Acceleo Application.

Getting started acceleo run as.png

The Acceleo launch configuration page opens, and you need to provide it with the sample model and target folder.

Getting started acceleo module launch.png

Due to changes... as you can see in the above figure means that you are to do something to workaround the problem. It is simple - add bin/ to the classpath in the MANIFEST.MF file. You can find it in the META-INF directory.

The second (better but harder) way is to use Java runner as the wizard suggests. It works fine with some metamodels but not with UML. It must be registered first if you want to deal with real models and not with just one or two classes. The registering is done by calling the UMLResourcesUtil.init(resourceSet) method in the method registerPackages of the class generated from the main acceleo module. To make this accessible, you should add dependency to the MANIFEST.MF.

Getting started acceleo module add UMLres dependency.png

Choose org.eclipse.uml2.uml.resources. If you start to write uml.r, you will find it quickly.

Getting started acceleo module add UMLres dependency plugin.png

Now you can go to the code and insert the call. Do NOT forget to save the manifest first.

Getting started acceleo module register UMLres.png

Now you can successfully run the project. The resulting Java file generated by this module file will look like this:

Getting started acceleo module java result.png

User code blocks

Acceleo supports two ways of specifying user code blocks in the generated code. User code blocks delimit portions of text that are only generated once, and preserved for subsequent generations. This is very useful in order to allow users to add code in some areas of the generated files while keeping the rest of the file under the control of the generator.

The first way of specifying user-code blocks is to use the standard [protected (id)]...[/protected] construct, as shown below (we've also added some queries in there to handle the package structure):

Getting started acceleo usercode 1 editor.png

The above module produces the following code:

Getting started acceleo usercode 1 generated.png

The second way, which is specific to generators that target the java language, is to add @generated annotations on the javadoc of elements that must be generated. Other elements (those that do not have such annotations in their javadoc, or in which the annotation has been slightly modified (i.e: @generated NOT or @not-generated ... or whatever you fancy)) are considered not to be modified by subsequent generations.

If a file contains at least one annotation @generated, the merge of the former java file and the newly generated one is delegated to JMerge_. @generated annotations must be added in the javadoc of the relevant java elements. They are not JDK5 annotations.

Getting started acceleo usercode 2 editor.png

In both of these examples, the code located in "protected" areas will never be overriden by subsequent generations, be it left as-is or modified by the user outside of the module (directly in the generated file).


Java services wrappers

We will now add a requirement that java beans should only be generated for Classes that have the Bean stereotype. This coud be done through Acceleo alone, but for the purpose of this tutorial we will use a java service (extension of the language) in order to check whether the stereotype is present on any given Class.

It is possible to initialize the content of a new Acceleo module file with content that comes from :

  • An existing Acceleo module file (a copy of this file is made)
  • Some java code that you need to access from your Acceleo templates

We will detail here the second possibility, which makes it possible to execute standard java code from any Acceleo template or query.

First, create the Java class we'll use as a service in Acceleo.

  • Right-click the org.eclipse.acceleo.module.sample package in the Package Explorer and select New > Class
Getting started new java class.png
  • In the popup that appears, change the Package field to org.eclipse.acceleo.module.sample.services and fill in the name field, we'll call this java Class UML2Services in this tutorial.
Getting started new java class 1.png
  • Finally, paste in the following code for this class :
 package org.eclipse.acceleo.module.sample.services;
 
 import java.util.List;
 	
 import org.eclipse.uml2.uml.Class;
 import org.eclipse.uml2.uml.Stereotype;
 
 public class UML2Services {
 public boolean hasStereotype(Class clazz, String stereotypeName) {
   List<Stereotype> stereotypes = clazz.getAppliedStereotypes();
     for (Stereotype stereotype : stereotypes) {
       if (stereotype.getName().equals(stereotypeName)) {
         return true;
       }
     }
     return false;
   }
 }

Now, what's left is to call this method from Acceleo. The easiest way to do so is to use the provided wizard. Right-click the org.eclipse.acceleo.module.sample.services package and select New > Acceleo Module File.

Getting started new service wrapper.png

In the wizard window, enter the relevant information in the fields : select the UML metamodel URI and change the name field to uml2Services. Then, activate the Advanced button in order to gain access to the advanced options.

Tick the Initialize Contents checkbox and select: Create a Java services wrapper. Finally, browse to find the UML2Services java file.

Getting started new service wrapper 1.png

This creates a new Acceleo Module file that contains a query (one per java method in your java class) whose role is just to delegate its behavior to the java class, thus making it accessible to your templates.

This is simply achieved thanks to the non-standard ``invoke`` Acceleo operation.

Getting started new service wrapper 2.png

Now to prevent Acceleo from generating files for classes that do not have the Bean stereotype, all that's needed is to import the uml2Services module in the generate module and nest the [file] block within an [if] block calling this service.

Getting started new service wrapper 3.png

Creating a main module

We recommend not to have multiple modules with an @main annotation, as it complicates the workflow (you have to launch multiple generations to create all needed files). On the contrary, we recommend creating a "main" module which role will be to delegate to all of the modules that will create files. Typically, this module will be placed alone in its own *.main package.

Let's create this launcher for the beans generation. First, right-click the org.eclipse.acceleo.module.sample package in the Package Explorer and select New > Acceleo Module File.

We will need to change all default information. First, append '*/main*' at the end of the parent folder field. Then, give a meaningful name for this module (umlToBeans in this example) and set its metamodel appropriately. As we generate on UML, we will also change the root type of our generation to *Package* (the root of our UML model). We will also untick Generate file and tick Main template in options.

Getting started new main module.png

Since this module contains a @main annotation, we will need to export its containing package (so that other Eclipse plugins may launch the generation). For this, open the META-INF/MANIFEST.MF file of your project, go to its Runtime tab, click Add and select the org.eclipse.acceleo.module.sample.main package. The tab should look like this when you are done :

Getting started export main package.png

Now, paste the following code in your umlToBeans module :

 [comment encoding = UTF-8 /]
 [module umlToBeans('http://www.eclipse.org/uml2/3.0.0/UML')/]
 
 [import org::eclipse::acceleo::module::sample::files::generate /]
 
 [template public umlToBeans(aPackage : Package)]
 [comment @main /]
 [for (aClass : Class | aPackage.packagedElement->filter(Class))]
 	[aClass.generate()/]
 [/for]
 [/template]

And that's it! you can now launch this main module in order to generate java beans from any UML model. Simply right click the umlToBeans.mtl file, select Run As > Launch Acceleo Application and select the model from which to generate and the target folder before hitting the *Run* button.

Creating a UI launcher

Now that your generation modules are ready, you may want to have some wizards to launch the generation from within Eclipse. You can use the generated java launcher in a manually coded action, but you can also use the New Acceleo UI project wizard. This wizard will create a new Eclipse project which will allow you to launch the generation with a right-click action on any appropriate model.

First, right click on your Acceleo project (org.eclipse.acceleo.module.sample) then select *New > Acceleo UI Launcher Project*.

Getting started new module ui project.png

Fill in the desired name for this project, then click next.

Getting started new module ui project 1.png

Select the generator project as referenced project, then click next.

Getting started new module ui project 2.png

Finally, enter the model filename filter (files for which the generation action must be proposed on ricght-clicks, *.uml in our example), and the java code for the target folder (leave it as-is to generate the code in the src-gen folder of the project containing the right-clicked model).

Getting started new module ui project 3.png

The wizard will create a new plugin with all the necessary code to display a new action for the selected model file that will generate code in the specified folder. The screenshot below shows the result of this plugin, a Generate Uml To Beans action on the *.uml* files.

Getting started new module ui project result.png



Acceleo Portal
Project Project · Installation · New & noteworthy · Release review · Policy API policy · Policy Retention policy · Next · Checklist
Features Acceleo Features · Runtime · Acceleo editor · Perspective Views & Perspective · Debugger · Profiler · Traceability · Wishlist · Interpreter · Maven
User documentation Getting Started (original) · Acceleo operations reference · OCL operations reference · Text Production Rules · Migration From Acceleo 2.x · Best Practices · Videos · FAQ
Developer documentation Source code · How to contribute · Compatibility · MOFM2T specification · OCL specification
Community Conferences · Blogs Twitter & Blogs · Professional Support · Report a bug