Tuesday, December 21, 2010

Acceleo vs Acceleo vs Xpand

We've recently had a good number of people asking for comparisons between Acceleo 2 and its new major version Acceleo 3. Some people also wondered how Acceleo ranked compared to the other trendy code generation tool, Xpand. The three have the same goal : generating text from models, let's take a closer look at their respective performances.

With the migration capabilities we have between Acceleo 2 and Acceleo 3, comparing those two has proven rather easy; comparing them with Xpand has been a little more trouble for me as I am not familiar to this tool. I still attained a result I believe to be interesting.

I didn't make in-depth comparisons between the tooling of each of these three tools, focusing on the generation performance only. GUI comparison may come later, when I have the courage :).

What I did compare was the generation performance for a given set of generation templates that I ported to all three of the technologies. The result is that all three tools (Acceleo 2, Acceleo 3 and Xpand 1.0.1) generate the very same java code, whitespaces excepted.

Each of the times outlined below is the average of three runs on the same machine :
- Intel Core 2 Duo 64 bits
- Dual core, 2GHz by core
- 4 Go RAM
- Windows seven 64bits

The version of Java installed on this machine was Java SE 1.5.0_22 64bits.

The Eclipse platform version was Eclipse Helios 3.6.1 (64 bits still). Each tool was installed within its own Eclipse with only its dependencies and the dependencies of the tests.

I've run two distinct use cases for this benchmarking :
- "Small" corresponding to the generation with a small model as input. I used UML.genmodel for this, which in turn links to UML.ecore, Ecore.ecore and Ecore.genmodel. When counting the content of the two main models used by this transformation, UML.genmodel and UML.ecore (just a basic count of eAllContents), I get a total of 14 420 elements.
- "Medium" corresponding to the generation of medium models as input. For this, I generated a metamodel with a fixed number of classes, enumerations and datatypes, then the corresponding genmodel. Like above, a basic count of the model content yields a total of 50 944 elements.

As far as generated files go, the "small" use case generates 217 java classes for a total of 200 921 lines of code. The "medium" use case generates 1 206 java files for a total of 838 273 lines of code.

All measures have been taken "at worst", launching the generation in a new Eclipse runtime (thus, nothing in cache, no plugin loaded yet). The times given here are in seconds, and they correspond to the average of three runs. One measure comprises the time to load the model, the time to evaluate the generation and the time to serialize the result.

Without further ado, here are the figures :

Acceleo 2 Acceleo 3 Xpand
Small 50 s
10 s
25 s
Medium 215 s
25 s
212 s

Being an Acceleo developper myself, I can only be pleased by these results ... Even though the test might be seend as biased as a result :p. All of the files needed to replay these can be downloaded from here. On that matter, as I am not familiar with Xpand, please don't hesitate to optimize the templates if at all possible (though the Acceleo 3 templates themselves don't use the latest evolutions of Acceleo 3.1).

Tuesday, October 12, 2010

Open World Forum Demo cup award 2010

The Open World Forum took place in Paris on September 30 and October 1. This was a great opportunity to discover open source tools and technologies, as well as getting to know great people of this field. The 2010 edition has attracted over 1500 participants from 40 countries!

Obeo was present and demonstrated the use of Acceleo 3 to generate android applications, this demo earned us the Demo Cup 2010 award! This award is given to recognize the most innovative and game-changer open source solution in its marketplace.

Acceleo, selected from 13 top nominees, received one of five prestigious trophies at the closing ceremony of the Open World Forum, awarded by a jury consisting of leading international experts in the open source world.

After the Eclipse Community Award in 2009, this prize recognizes the constant efforts of the Acceleo team & community to provide a powerful tool of the highest quality.

Monday, August 16, 2010

User interface improvements in Acceleo 3.1

Acceleo 3.1.0 is due June, 22 2011 along with Eclipse Indigo ... seems far, but not as far away as we sometimes hope for with all the features we'd like to add in our products.

Because of this, we've already started implementing some of the (many) improvements we'd like to make in the Acceleo editor : support for template, query and module documentation, support for more markers to display feedback to the user (information, warning, "overriding" link...), support for tasks in the template (TODO, FIXME, ...), improvement of the oultine, feedback on the non-printable characters that will be generated ...

Stephane Begaudeau is reponsible for most of these first additions, you can find a list, detailed explanations and screenshots in this great post.

Most of these improvements have already found their way in the source code and will be available in the 3.1M1 release of Acceleo tomorrow, care to test? Or are there features you would like to see in the Acceleo module editor? Don't hesitate to take part in the discussions, raise bugs or provide feedback on either bugzilla or forum :).

Wednesday, June 30, 2010

Using code generation under ClearCase

Those of you that know ClearCase also know that it requires the user to check out the file he wishes to edit before any editing can be done; kind of trying to edit a read-only file : you need to remove the read-only flag before anything else. Of course, this doesn't fit well with code generation tools such as Acceleo since the aim of such tools is to edit (or create) a number of files at once.

Until now that is :). Acceleo can now be used in conjunction with ClearCase or other pessimist-locking Version Control Systems (VCS). How does it work?

You might have noticed the "getGenerationStrategy()" method of the Java class we generate for your main mtl files; this is the method that matters for us. You simply need to change it from its default "return super.getGenerationStrategy()" to "return new WorkspaceAwareStrategy()" and you're done! Acceleo will now prompt the users of your generators to check out the files before attempting to modify them.

Two things to note :
  • You must change the javadoc of "getGenerationStrategy()" so that it doesn't contain "@generated" anymore : delete this tag, change it to "@not-generated", change it to "@generated NOT"... just don't leave this tag as-is or the Acceleo builder will override your change.
  • You cannot use this strategy in standalone mode, its goal is to integrate with the Eclipse workspace and its team providers.
The use case with ClearCase or pessimist locking VCSs is obvious, but you might realize that there is more to it that just these. You could be trying to regenerate a file that you set as read only, a file under SVN that requires a lock...

For example, with SVN you can set the property "svn:needs-lock" on a file to prevent any edition without prior locking. If you attempt to regenerate a file with such a property set with Acceleo, here is what you will get :

"java.io.FileNotFoundException: [...]\Library.java (Access denied)"

Pretty mean, huh? If you make use of the WorskpaceAwareStrategy though, you will get this instead :

All you have to do is to tick off the files for which you wish to take the lock. Files you do not check will not be locked for edition.

Friday, June 11, 2010

Package with URI '*' not found

I believe most of the users of EMF (developers or adopters alike) have seen this message at least once; and most probably wondered what was going on :).

This error message indicates that the package which NsURI is '*' hasn't been registered in the Package registry. Most of the time, that means you either a) launched your program standalone and didn't register the package correctly or b) you haven't installed the plug-in that provides that metamodel.

With Acceleo, encountering this exception is even more likely than normal, as the launch configuration for our generations allow for both standalone or plug-in generations. Selecting standalone without registering the needed package will inevitably lead to this error.

Solving it is easy : it is a matter of registering the needed packages (and, optionally, resource factories). How is it done? Here is the most classic example with UML :

Package with uri 'http://www.eclipse.org/uml2/2.1.0/UML' not found.

What do I need to do for my UML model to be loadable :

EPackage.Registry.INSTANCE.put(UMLPackage.eNS_URI, UMLPackage.eINSTANCE);
.getExtensionToFactoryMap().put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE);

The same goes for every metamodel you might need, simply change UMLPackage by XxxPackage according to your metamodel. The Resource Factory is mandatory for UML, but your metamodel might not need one; simply ignore this line if you don't have a custom factory.

You need these two lines to be before the point where your model is loaded. For Acceleo, this is done in the generated Java launcher : simply change the implementation of the registerPackages and registerResourceFactories method to add these needed lines.

Tuesday, June 8, 2010

New Acceleo homepage

The Acceleo homepage now makes use of the template provided by Heiko Behrens.

You've seen it with MoDisco, you've seen it with Xtext, it's now our turn to change skin :).

This also makes use of the changes brought to the CSS by Fred Madiot.

Thanks to both of them !

Tuesday, June 1, 2010

What's new in Acceleo 3.0?

Acceleo 3.0 is on its way out. It is currently accessible in its third Release Candidate (RC3) version. The complete list of improvements and bug fixes that have been implemented in this version since the last stable release (version 0.8.1, see my previous post for explanation on this branch's version numbering) is humongous; following is the list of the most important ones. I may be succinct on the description of some of these, but you can get a full explanation of all of them in the Acceleo documentation, namely the User Guide. Be warned though, this will be a huge post :).

Compatibility and upgrading
  • Acceleo 3.0 is compatible with the three latest releases of Eclipse; Eclipse 3.4 (Ganymede), Eclipse 3.5 (Galileo) and Eclipse 3.6 (Helios). However, there are some limitations to this compatibility we maintain due to the changes that were implemented in OCL since then. For one, Acceleo modules that compile in Helios may or may not compile in Galileo and Ganymede (this will depend on the OCL features you make use of). However, Acceleo modules that compile in a given version will always compile in the subsequent Eclipse releases. Likewise, a module that has been compiled in Helios may be launched in Ganymede regardless of whether it would compile or not in that version, as our runtime shouldn't suffer from OCL breakages and improvements. All information about the compatibility will be maintained on the wiki.
  • We provide migration facilities for those of you that own Acceleo 2 templates. Specifically, we allow for the automatic migration of Acceleo 2 generation projects to Acceleo 3 projects. The automatic migration takes care of everything that could possibly be automated, leaving for you to fix no more than the Acceleo 2 features that don't have an identified mapping to Acceleo 3, or those few features that require a human hand to convert intelligently. The team is at your disposal for help if there still remains things you don't know how to convert to Acceleo 3 on the usual communication channels : the M2T newsgroup, mails, comments on this blog...
Tooling improvements
New views have been introduced to help you on several aspects of the generation cycles : module definition, launching, debugging. I'll detail each of these views one after the other.
  • First of all, the Result view allows you to get feedback on the traceability information we could retrieve during the evaluation of your modules. As long as this view has been opened, Acceleo will record every bit of information it can to synchronize your generated text with the generation module and source model. Ever wondered why such or such portion of text has been generated one way or another? What part of your generation module has generated the name of such or such method? From which element of your model has been generated such or such import? This is the view you can use to retrieve these pieces of information.
  • Next comes the Overrides view, which can be used to easily create templates or modules overriding other that are present in your instance of Eclipse. It will display every single module located either in your installed plug-ins or your workspace. All of these can be browsed down to the template level and a check box allows you to select those you wish to override. Once selected, you simply have to use the content assistant in the Acceleo Editor (CTRL+SPACE by default) and validate selected overrides for all of the overriding templates to be added to your module.
  • Last but not least, the Generation Patterns view has been introduced to help you implement behavior for an interface/class and all (or a subset of) its subtypes. For example, let's say you wish to implement a template named javaName which will generate the name of any classifier. This template will need some default behavior for interfaces and specific behavior for some classifiers. Open the Generation Patterns view, tick [template] for all selected types in its top part, and all of the types you wish to generate a template for in its bottom part. Once done, the content assist in the Acceleo editor will give you the choice [template] for all selected types which you just have to choose in order to generate all of the templates you asked for. Now that you no longer risk forgetting one or more subtypes, it is left to your discretion to implement the behavior for each of them.
  • Acceleo now provides a built-in profiler that can be used to keep track of evaluations and identify (and, hopefully, fix) bottlenecks in your generation process. The profiler is accessible through a right click on the module which execution you need to profile and the menu item Profile As => Acceleo Application.
  • The Acceleo debugger now provides you with the list of available variables at a given point in the evaluation process, along with the values of these variables for a given stack frame. Moreover, the displayed stack frames now represent Acceleo module element corresponding to your current expression stack. As for the previous release, debugging templates only requires you to set breakpoints in the Acceleo modules as you would usually with Eclipse : open an editor, double click in the left margin on the line you wish the breakpoint to be set, and launch the generation through the menu Debug As => Launch Acceleo Application.
  • Whenever possible, the warnings and errors Acceleo logs when an evaluation fails now sport the expression stack (with the lines they're at in the module files) instead of a stack trace corresponding to the Java code that was being executed at the time. This will allow for way easier debugging that ever before.

Editor Improvements
Apart from the performance improvements and minor bug fixes, the Acceleo module editor now provides refactoring actions and quick fixes.
  • First of all, you can now use the “usual” shortcut ALT+SHIFT+R to rename either modules, templates, queries, variables, ... in a coherent manner. This very same action can be accessed from right-clicking and selecting Refactor => Rename. The interface will allow you to preview the changes before validating them.
  • Portions of the module elements can be extracted as new templates through right-clicking and selecting Refactor => Extract Template (or simply using the shortcut ALT+SHIFT+T). Do note, however, that the selected text needs to be consistent. You cannot randomly select text that spans blocks of code and expect an adequate result.
  • The module editor now highlights all occurrences of the selected element when you click on it. For exemple if you place the cursor on the name of a template, all invocations of this template will be highlighted and markers will appear on the right ruler of the editor to indicate them.
  • Acceleo now provide quick fixes for some of the syntax errors detected in the editor, notably the possibility to create template or queries of a corresponding name.
  • It is recommended to use a bottom-up approach when developing generators ; Acceleo now eases this process by allowing you to initialize the content of a generation module with an example, and offering specific actions to transform these examples (static text) in dynamic OCL expressions. For example, changing all occurrences of MyClass to [c.name.toUpperFirst()/] in a single click.

Improvements and simplifications of the language
  • The MTL specification defines a standard library that offers a set of utility operations; in addition, Acceleo provides a non standard library to provide operations that greatly simplify the language and allow you to write more concise expressions, but are not part of the specification. This library has seen many additions since the 0.8 version, with things like Collections::sep(String) to insert a separator in-between every element contained by a collection, String::matches(String) to check whether a given String matches a regular expression, Collection::filter(Type) that can be used to filter out of a collection all elements that are not instances of a given type, Collection::reverse() to reverse the content of a given Collection... Take a look at the Acceleo documentation for a full reference of both standard and non standard library, along with the reference of the OCL standard library.
  • Acceleo allows you to alter the build mode, either Strict or Lax MTL compliance. Strict compliance meaning you'll get a warning for each use of a “non standard” operation.
  • Those of you that are familiar with the 2.x stream of Acceleo will be pleased to know that Acceleo 3 now provides the same post-processing facilities as its ancestor through the addition of a post directive on templates. Which allows for the modification of the text generated by a template “after generation”. For example, post(trim()) allows you to properly indent the content of the template while still leaving you the possibility to trim all unnecessary white spaces from the generated text.
  • The “+” operator can now be used whenever one of the operands is a String for concatenation, in order to avoid the verbose concat(String) OCL offers.
  • You can now use properties files to customize your generations through the addition of 4 variants of a getProperty operation in Acceleo 3. Once again, the operation reference can be looked at for the description of those services.
  • We made use of the facilities OCL provides in order to further simplify the navigation language : iterators of our [for] blocks are no longer mandatory (they'll be implicitly declared if needed and self can be used in their stead), you no longer need qualified names for your types when the metamodel is declared on the module header (or if it can be inferred from another of the declared metamodels), casting through oclAsType for all redundant expressions is no longer necessary...
  • For those expressions where OCL doesn't allow us to simplify the language, we added non standard operations. For example, sequence->select(oclIsKindOf(Type)).oclAsType(Type) is obviously redundant, but OCL doesn't allow for this expression not to define the explicit cast. In Acceleo, you can now write sequence->filter(Type) instead (see also my post on this specific issue).
  • Acceleo now allows for control characters (\n, \t, \'...) in OCL expressions.
  • Acceleo [for] blocks now declare an implicit “i” variable that can be used to retrieve the iteration count. For example, [for (Sequence{4, 5, 6})][i/], [/for] will generate 1, 2, 3.

As advertised by Jonathan in one of his latest posts, the Acceleo documentation is complete and can be accessed from the integrated Eclipse Help through Help => Help Contents, in the Acceleo Model To Text category. We provide everything you need in order to get started with Acceleo; quick start, tutorial, user guide... and the full reference of OCL standard library and Acceleo standard and non standard libraries complete with explanations of the operations and examples.

Thursday, May 27, 2010

Acceleo : OCL made simple

It was recently asked on a mailing list how one would order the elements they iterate over in an Acceleo for loop. The elements were UML ControlFlows as in :

- Package
|-- Activity
   |-- ControlFlow1
   |-- ControlFlow2
   |-- ControlFlow3

The first answer that came to mind, using standard OCL, was :

[for (cf:ControlFlow |c.ownedElement->select(a|a.oclIsKindOf(ControlFlow))->sortedBy(e: Element | e.oclAsType(ControlFlow).name))]

Pretty verbose ... If we instead make use of the implicit iterators Acceleo offers, the expression can be simplified to

[for (c.ownedElement->select(oclIsKindOf(ControlFlow))->sortedBy(oclAsType(ControlFlow).name))]

But this still sports the redundancy of filtering from a list only the elements of a given type (select) and then casting the elements to ... that very same type (oclAsType). This is due to OCL not allowing Acceleo to infer the return type of the select operation. Starting from Acceleo 3.0, this expression can also be written

[for (c.ownedElement->filter(ControlFlow)->sortedBy(name))]

Now that's better!

Wednesday, April 28, 2010

Acceleo API and properties files

This post is aimed at anyone that depends on or make use of the Acceleo versions built and provided within the Helios release train, namely 0.9M1-0.9M5 and 3.0M6. If you are not concerned, feel free to ignore it altogether ^^.

We added support for ".properties" files in Acceleo in the latest development version (this support appeared for 3.0M1, at the time named 0.9M1). However we realized that this first version of the properties handling left no place for customization/overriding of properties ; no place for internationalization ; and deployment of generation modules as plugins would most likely cause issues with properties lookup. Bug 311045 and bug 311068 have been opened to track these issues.

If you are one of the early adopters that made use of the property support, you'll need to cope with a little change for the M7 build : in the generated class was an "addProperties" method which allowed you to registered the full path to the properties file that was to be loaded. For example if you had a file named "messages.properties" in package "sample" of plugin "org.eclipse.acceleo.sample", you had to register the path "platform://plugin/org.eclipse.acceleo.sample/sample/messages.properties".

You will now have to return a list through the method "getProperties" (well, "addProperties" is still there yet deprecated), and this list will have to contain "sample.messages" (that is, .) ; and properties file need to be located in source folders.

Likewise, if you had set anything as "generated NOT" in the generated launcher, you will have to manually go through some minor API changes as we ended up creating a common superclass for all launchers. Specifically, launchers now "extends AbstractAcceleoLauncher", and what was once private or protected is now mostly public. This means previously generated launchers that had set any method as "generated NOT" might have to enhance the visibility from private to public. Take note that previously generated launchers that have been built and deployed will not fail and can still be used as is, though enabling re-use of your generator can only be done by letting Acceleo regenerate it (or simply code yourself to take these changes into account).

Sorry about these changes (especially past M6), but we really thought best to remove the bug-prone behavior instead of trying to maintain it since it had never been released in a stable build. The new API should allow for a real use of property files and enhance the re-usability of any generation module.

If you wish to have a look at these changes and cope with them before M7 goes live, they are all accessible in the integration build I201004291415 that went live today (see the download page for the zip or all-in-one update site downloads).

If you have any doubt or questions about these issues, feel free to answer the m2t newsgroup thread I started with a copy of this post.

Tuesday, April 13, 2010

OCL tips and tricks

Acceleo is entirely based on OCL (Object Constraint Language) for all of its model navigation syntax. Though we did simplify it as much as possible for Acceleo (getting rid of redundant casts, increasing the standard library, overriding operators, ...), there are still some things that might cause problems to any beginning user.

Here are a few of the most unsettling language particularities :
  • Operations or features conflicting with reserved OCL keywords (UML anyone?). For example, if your model has a class "Operation" with a feature named "body", then writing "myClass.body" in OCL will result in a somewhat cryptic error : "invalid token 'body'".

    The trick to access such features in OCL is to prefix the feature name with an underscore. For this example, you should have written "myClass._body".

    For the record, the full list of OCL reserved keywords as per the last available OCL version, 3.0, is as follows :

    • and
    • body
    • context
    • def
    • derive
    • else
    • endif
    • endpackage
    • if
    • implies
    • in
    • init
    • inv
    • let
    • not
    • or
    • package
    • post
    • pre
    • static
    • then
    • xor

  • Accessing enumeration values. This might sound obvious to OCL experts, but how would one compare feature values to set enumerated values? The trick here is to qualify the access. For example if you wish to check that an UML operation's visibility is "public", here is what you would do in Java : "if (operation.getVisibility() == VisibilityKind.PUBLIC".

    The OCL equivalent is "if (operation.visibility = VisibilityKind::public)".

  • There is no "elseif" in OCL ; remember to close each individual if properly with endifs : "if (...) then ... else if (...) then ... else ... endif endif"
I believe these are the most annoying (as in "the most subject to cause weird compilation errors") OCL features ; don't hesitate to add yours :p.

Wednesday, March 17, 2010

Acceleo graduation, version jumping and maintenance

Quite a few monthes ago I talked about the history of Acceleo and why its version number were regressing. Well let's talk about version jumping now :p.

Acceleo is a code generator with its own history and user community ; over the years, it grew from its first stable release to its current 2.6 version. Yet, we (the Acceleo dev team) thought that the future of code generation lied in the OMG standard "MOF Model To Text Language" (MTL) based on OCL.

An important change with this version is its switch from a self-hosted project to an eclipse foundation project. Following Eclipse rules, the project "Acceleo" was required to have an incubation phase, and this incubation called for version numbers 0.*. Started a little more than two years ago, this incubation phase is almost ready for its end.

We plan to have Acceleo graduate along with the Helios (Eclipse 3.6) release which is due to be out on June 2010. This usually means the plugin grows from version 0.9 to version 1.0. However, in order not to unsettle the existing adopter community and stay coherent with Acceleo version history, we plan to have Acceleo jump from version 0.9 (its last incubation version within Eclipse) to version 3.0 (as the last stable release of Acceleo out of Eclipse was 2.6).

At first, we planned to implement the version jump after the official release review in June 2010 ; yet to avoid unneeded unstability and after double-checking with the Eclipse management organization, we did this change before the last "pre-release candidate" milestone. With this latest build, Acceleo then jumps from '0.9.0M5' to '3.0.0M6'.

Take good note that this version jam is for those of you who plan to give (or were already giving) the new Acceleo a try. Acceleo 3.0 already sports awesome stability and a level of functionality close to if not equal to its 2.x stream to which you might be accustomed. As for this maintenance stream, we have a corrective version incoming and a 2.7 version will be out any week now.