Tuesday, November 24, 2009

Retrospect: DemoCamp in Berlin

Yesterday I attended the Eclipse DemoCamp in Berlin. It took place at Fraunhofer Fokus, and (as the last democamps) it was organized by Tom Ritter (thank you, Tom!). This time, there were ten (10!) presentations, seems as if we should organize a DemoDay next time. The camp started with a nice welcome talk by Ralph Müller, encouraging the audience to become Eclipse members (I will talk with my employer about that, promised ;-) ) and visit Eclipse Summit Europe (I won't miss it). Kristian Duske (committer on the GEF3D project) presented a "GEF3D Based Editor for the GMF Mapping Model", which was the subject of his diploma thesis. His editor enables the creation and editing of the GMF mapping model using simple drag-and-drop mouse operations. In contrast to the tree-based GMF editors, all involved models are visualized in a graphical manner, and since all models are visualized in a single 3D scene, inter-model-connections are visible, too. I really like the idea and his presentation, but since I was his tutor, I'm not really an impartial observer ;-)
Fig 1: Kristian's 3D GMF Mapping Editor
Martin Esser then demonstrated a small editor he has created with GMF (unfortunately without Kristian's 3D editor ;-) ) for variability models (aka feature diagrams). The challenge is to implement these arcs connecting edges of optional or alternative features. I usually draw these diagrams using OmniGraffle, and although there is a stencil for these diagrams available, it is painful to adjust these arcs -- a GMF based editor would be a great help. Maybe Kang et al designed these diagrams in order to test the abilities of programmers of graphical editors... (BTW, I just stumbled over this Eclipse project proposal, they want to provide a graphical editor as well) It seems as if there is an Xtext presentation at every democamp ;-), and of course there was a talk about it in Berlin, too. Peter Friese gave a short overview of this really nice tool for creating editors (and more) for textual DSLs. I have attend a couple of Xtext presentations (e.g. at ESE 2008 and 2009), and although all these presentations used different slides and were presented by different persons, the slides are always magnificent (with great photos and nicely illustrated). Maybe they have an Xtext based tool for generating these slides... hmm... Ralph Müller mentioned something about Ytext in his keynote, maybe this is a new tool for generating presentations? After a short break (with Eclipse sponsored sandwiches and soft drinks ;-)), Marcus Engelhardt demonstrated a tool called Metrino for measuring models. Metrics can be defined using OCL for UML or Ecore based DSLs, and the tool creates nice reports and radar charts. IMHO model metrics are an important tool for modelers, and I always have the plan to create tool with GEF3D in order to display the metrics on top of the diagrams (using the city metaphor) as illustrated in Figure 2... Marcus, if you'd like to combine that with Metrino, I would be happy to assist you!
Fig. 2: Visualization of metrics with GEF3D
Joachim Hänsel and Jaroslav Svacina introduced their tool EvoTest for creating tests automatically with evolutionary techniques. I know that tests are very important, but (shame on me) I'm neither an expert for testing nor for evolutionary techniques. However, their tool looks very interesting, and I was impressed by the ability of that tool to generate white box tests considering path coverage. Next, Martin Köster talked (slides are available here) about how he created an Eclipse based IDE for the Clojure language, a Lisp (that language driving you crazy with brakets) dialect for the JVM. It was very interesting to learn how he used the DLTK in combination with his own ANTLR parser. There seem to be a lot of issues addressed by Xtext and DLTK. I wonder if it would make sense to integrate these two tools. Stephan Herrmann then presented a new episode of the famous Object Teams series. After a short "previously on OT" flash back (summarizing OT as a great tool for reusing existing components in a flexible (via AOP techniques) yet controlled (via modules and a role-team-concept) manner), the story continued with a special and important problem: persistence. He explained how it is possible to use OT in combination with O/R-mappers -- with minimal effort by using OT techniques. Actually, this topic was subject of a diploma thesis (in german language) by Olaf Otto. OT is a proposed Eclipse project, and I hope it will become a real Eclipse project, soon. Igor Novakovic demonstrated a powerful tool called SMILA. It is an Eclipse project for setting up tool chains for querying, processing and extracting data. In his demo, he showed how to combine some cool Fraunhofer tools for image recognition with a search engine (Lucene) (probably other tools were involved as well). The nice thing about SMILA is that in the end all these tools are combined in a way that some data can be queried in a very simple manner (e.g. HTML formular). In the demo, some chemical structures could be searched in a collection of research papers. Simply querying the text content wouldn't be that thrilling, but in that case, a tool analyzed the figures in the papers and presented the molecules using Jmol. Some years ago I integrated a search engine (Verity Information Server) with a CMS based on StoryServer, and a tool like SMILA would have been a great help (I assume that with SMILA I would have spent days instead of months to accomplish that task...). Finally, Enrico Schnepel presented a small framework called emf.observables for simplifying EMF databinding. His cool (Prezi based) slides are available, too. Actually it is a small yet helpful tool, generating some plugins next to your EMF model implementation with some wrapper classes hiding the complexity of EMFObservables/IObservable. It was a really interesting and inspiring evening: A big thank you to all the presenters. See you all again at the next Berlin Eclipse DemoCamp (or Day ;-)).

Wednesday, September 30, 2009

String.format vs. MessageFormat.format vs. String.+ vs. StringBuilder.append

Usually I'm not a performance hacker, i.e. I seldom use the final keyword, and I dare to use List.size() in loop expressions. But I'm a little bit sensitive when it comes to string operations, as they can cause severe performance problems, and sometimes security issues as well, e.g., if an SQL query is to be created (ok, bad example, one can use PerparedStatement instead of hacking an SQL string). For logging I often have to concatenate strings, such as
if (log.isLoggable(Level.INFO)) {
    log.info("Command created - cmd=" + cmd); //$NON-NLS-1$
Actually I'm not writing lines like this myself, I let log4e do the job -- I really love that tool! But sometimes these string concatenations are hard to read, using a String.format or MessageFormat.format would make it much easier. Here are some examples:
foo(String.format("Iteration %d, result '%s'", i, value[i%2]));

foo(MessageFormat.format("Iteration {0}, result ''{1}''", i, value[i%2]));

// single line:
foo( "Iteration " + i + ", result '" + value[i%2] + "'");

// multi line:
String s;
s = "Iteration ";
foo(s); s+= i; foo(s); s+= ",\nresult '";
foo(s); s+= largeString(i); foo(s); s+= "', '"; 
foo(s); s+= largeString(i+1); foo(s); s+= "'";

foo(new StringBuilder("Iteration '")
    .append(i).append(", result '").append(value[i%2]).append("'")
(Update: the multi line test was added after daObi and Laurent commented the first version) Hmm... maybe the "+" isn't that bad ;-) I do not understand why String.format andMessageFormat.format have these different notations, and frankly I seldom get the format string right in the first run. So, besides the aesthetics, what about performance. What would you guess? My guess was StringBuilder would be the fastest, followed by the format methods, and the String operator "+" would be the slowest as new Strings are to be created all along. I run a little test (calling these methods 100000 times, foo() is doing nothing and was, besides other things, only added in order to avoid too much compiler optimizations, although I have no idea if that worked ;-) ). Note that in the test only a few strings are concatenated, but I think that's a typical example and it was the setting I was thinking about to use format methods instead of string concatenation (and it's quite similar to many toString methods). I was surprised by the result:
String.format:757 ms
MessageFormat.format:1078 ms
String +:61 ms
String + (multi line):162 ms
StringBuilder:74 ms
Gosh! The "+" operator clearly is the winner! It is 10 (ten!) times faster then the format methods. 10 times, can you believe that. I was really surprised, and frankly, I couldn't believe it. (Update: daObi and Laurent explain it, see their comments below). Thus I changed the test, assuming the compiler tricked me, but I always got more or less the same results. I figured it may be the size of the strings, so I also changed that. That is, I used large strings (with 70.000 characters, the method returns one of two strings in order to avoid compiler optimization) in the concatenation:
for (int i = 0; i < n; i++) {
    s = MessageFormat.format("Iteration {0,number,#},\nresult ''{1}'', ''{2}''", i,
   largeString(i), largeString(i+1));

for (int i = 0; i < n; i++) {
 s =  "Iteration " + i + ",\nresult '" + largeString(i) + "', '" + largeString(i+1) + "'";
Actually, the test is a little bit unfair, as in all cases at least the result string has to be created (i.e. also the format methods have to create strings), but at least the string is rather long. The result string s has a length of 140027 characters, so this is a pretty long string, isnt't? Here are the result of the long-string-test:
String.format:584 ms
MessageFormat.format:816 ms
String +:621 ms
String + (multi line):867 ms
StringBuilder:555 ms
Yeah! Now we have the order I expected in the first place: StringBuffer.append is the winner, followed by String.format. MessageFormat.format has a little problem and is even slower than the String concatenation. But compared to the result of the first test, all methods are at the same speed. So, what did I learn? First, I will use the plain and simple string concatenation in the future more often, as it is easier to write in many cases compared to some weird format strings. I will use String.format only if I probably need to translate my code, since this is easier to translate a format string than changing the code (if the order of the sentence components change in another language). And, of course, I will use StringBuilder if large strings have to be concatenated, but I think I use it less in toString-methods. And maybe I'm going to read a book about performance hacking -- do you have any recommendations? Anyway, this test also teaches me (again) that good performance is not (only) a question of single statements, but a question of good algorithms and good design in general. Note: Actually this is not the first time I was surprised by the result of a preformance test. I did a test once comparing the performance of different class library designs in case of a math library for matrices and vectors. I have documented the test in the LWJGL forum, and its results influenced the design of the GEF3D geometry package (see package documentation).

Wednesday, July 1, 2009

User Report: Migrate from oAW Xtext to TMF Xtext

With Eclipse 3.5 comes the new version of Xtext, called TMF Xtext. Since I had to switch to Eclipse 3.5 in order to keep GEF3D running on the latest Eclipse version, I decided to migrate from the old openArchitecture Xtext (oAW Xtext) to the new TMF version. Fortunately the Xtext documentation contains a section about migrating from oAW Xtext to TMF Xtext. Frankly, I was a little bit afraid (never change a running system). But at least I hadn't implemented any content assist or other editor extensions yet, so I hoped that it wouldn't be too hard. Before you read on, please note that I'm only an Xtext user. I don't know any internal details about Xtext. Maybe some of my problems can be solved more efficiently, if that is the case, I would be more then happy if you leave me a comment. My first intention was to migrate my already running grammar as fast as possible, with as few modifications as possible.

The Setting

I have written a model transformation language, and it consists of an Xtext grammar (with about 90 rules), an interpreter for executing the language, and other things which I didn't expected to be involved in the migration, as a debugger component or other user-interface stuff. An Xtend-based M2M transformation exists which modifies the generated ecore model in order to set some default values, add some workarounds for existing oAW bugs, and do other things. In order to migrate my application, I had to
  1. migrate the grammar
  2. adapt the M2M-transformation
  3. adapt client code which uses the model and the Xtext API
In the following old versions are highlighted with a light red back and the new ones with a light green background.

Migrating the Grammar

As described in the Xtext documentation, I had to replace "Enum" with "enum", and add two new lines at the beginning of the grammar. Since "with" has become a keyword. Thus I had to rename "with" in my grammar :
RuleXY: ... ( "with" with=Block)? ...
RuleXY: ... ( "with" _with=Block)? ...
This also caused some small changes in the model and the client code. Is there a way to use Xtext keywords as a reference names?


Apparently the parser generation (or some settings) has changed, too. E.g., the following rule worked with the oAW Xtext version:
ParameterReference: QualifiedParameterReference|SimpleParameterReference;
SimpleParameterReference: type=Type (name=ID)?;  
QualifiedParameterReference: type=Type name=ID;
The idea of these rules is to force the definition of a name in case of qualified parameter references and to make it optional in simple ones. Unfortunately these rules are not working with the new version. Since ANTLR is a LL-parser, there are some constraints on how to define the grammar. There is a document explaining how to remove backtracking from a grammar, unfortunately some of the described techniques cannot be used with Xtext. In some cases I was able to fix the problem by rewriting my grammar, as in this example: I simply had to reorder the first rule:
ParameterReference: SimpleParameterReference|QualifiedParameterReference;
SimpleParameterReference: type=Type (name=ID)?;  
QualifiedParameterReference: type=Type name=ID;
In some cases I couldn't find a solution (maybe it is possible, but I'm not an LL/LR-expert). Actually I'm not the first one with this problem, and there is a posting in the TMF newsgroup about this. If you cannot rewrite your grammar, you need backtracking (and lookahead). Thanks to this posting, I was able to fix the problem. I had to edit the MWE-file from
<fragment class="org.eclipse.xtext.generator.AntlrDelegatingFragment" />
<fragment class="de.itemis.xtext.antlr.XtextAntlrGeneratorFragment">
   <options k="2" backtrack="true" memoize="true"/>
Note that you have to install the itemis generator fragment from http://download.itemis.com/updates as described in the Xtext documentation (page 62). Maybe I'm going to "left factor" my grammar in a future version, but for now I only wanted to get my application running.

Lexer Rules

In the oAW version, lexer rules were defined with the keyword "native", which has been changed to "terminal". Not mentioned in the migration guide yet: INT was redefined in the new version. I had rewritten the definition in the old version in order to remove the optional sign (as my language is handling this itself). This is the old INT definition:
Native INT: ('-')?('0'..'9')+ 
And here's the new one:
terminal INT: ('0'..'9')+ 
In my case I could remove my own definition since the new one matches my requirements. In other cases, this might be a trap. According to the documentation, it should be possible to define the type of a terminal rule now. I tried this as follows:
terminal FLOAT returns ecore::EFloat: ('0'..'9')*'.'('0'..'9')+;
As a matter of fact, the code is generated as expected, but the parser still returns a String, which leads to a ClassCastException. So I removed the type definition and added a convenient method to my model, as described below. I assume this is a bug or something, I will file a report later on ;-). Since the old version always returned Strings, my code was prepared for that, anyway.

OrmPackage missing

I don't know exactly why or when, but at some point in time my grammar file contains got an error marker:
- WrappedException: java.lang.ClassNotFoundException: com.sun.java.xml.ns.persistence.orm.OrmPackage"
This bug seems to be fixed already, fortunately it is possible to generate the model and code from the grammar, even with this error.

Unassigned Actions

In the oAW Xtext version, a model element was assigned whenever a non-abstract rule was hit. My grammar contained the following rule:
NullLiteral: "null";
This rule is not working with the new TMF Xtext version. As found in the documentation "by default the object to be returned by a parser rule is created lazily on the first assignment". Although I've read that passage, I was not aware of the consequences. In the new version, an element is not automatically created when the rule is hit, but only when an assignment is to be executed. That is, a rule which contains only terminals does not create a model element, as in the example above. While this first example is obvious, the problem is sometimes hidden. Here is another more tricky example:
Block: "{" (statements+=BlockStatement)* "}";
If no "BlockStatements" are specified, that is in case of an empty block ("{}"), no block element is created at all. I posted that problem to the newsgroup, and Sebastian Zarnekow immediately solved my problem (Thank you very much, Sebastian!). The solution is to use unassigned actions, which forces the creation of an element of the specified type. So I had to change the rules above as follows:
NullLiteral: {NullLiteral} "null";
Block: {Block} "{" (statements+=BlockStatement)* "}";
I figure this is a bitchy trap, especially if there is an optional assignment.

Model Changes

I'm already using an Xtend M2M-transformation to adjust the generated ecore model. TMF Xtext supports this mechanism, I simply had to rename my Xtend extension into MitraPostProcessor.ext (Mitra is the name of my language, by the way).

Enumeration NULL values

There are some adjustments necessary due to changed behaviour of Xtext. Most notable: There is no "NULL" value generated for enumerations. Also, it is not possible to define a hidden enumeration in the grammar, which might could have solved that problem. IMHO, this is a major drawback, as this makes a postprocessing of the created ecore file necessary. But they can be added to the M2M transformation. Unfortunately, I didn't got this problem solved with Xtend, I posted that to the TMF newsgroup. This is at least one solution using Java, although I would prefer a pure Xtend solution:
process(ecore::EPackage p):
 addNullValue(p, "VisibilityModifier") ->
 ... ;

Void addNullValue(ecore::EPackage p, String toEnum):
 doAddNullValue( (ecore::EEnum) p.getEClassifier(toEnum) );
Void doAddNullValue(ecore::EEnum e):
 JAVA de.feu.MitraPostProcessorHelper.addNullValue(org.eclipse.emf.ecore.EEnum);
And this is the Java extension:
public class MitraPostProcessorHelper {

 public static void addNullValue(org.eclipse.emf.ecore.EEnum e) {
  for (EEnumLiteral literal : e.getELiterals()) {
   literal.setValue(literal.getValue() + 1);
  EEnumLiteral nullLiteral = EcoreFactory.eINSTANCE.createEEnumLiteral();
  e.getELiterals().add(0, nullLiteral);
In order to make a literal the default value, it must be the first defined literal. This is why e.getELiterals().add(0, nullLiteral); is required, simply adding the literal with e.getELiterals().add(nullLiteral); doesn't work.

Java Body Annotation in the Ecore Model

In the old version, Xtext didn't create the genmodel and no code. I added this feature and I also edited the generated code after is was created using oAW extension. Since Xtext is doing the code generation now automatically, I didn't feel that comfortable with manually editing the generated model code anymore. So I decided to add Java annotations to the ecore model in order to add some tiny helper methods. This is how body annotations are added to an ecore model in Xtend:
Void addJavaBodies(ecore::EPackage p):
 let ecorePackage = p.getEcorePackage():
       'return upper==-1 || upper>1;') ->
This is a hack in order to retrieve the ecore package itself. This is usually
done with a Java extension, but I did not want to add a Java extension here.
The trick is to retrieve the package by navigating to the container of an ecore
type (here a String).
cached ecore::EPackage getEcorePackage(ecore::EPackage p):
  ( ((ecore::EClass) (p.getEClassifier("MetamodelDeclaration")))

create ecore::EOperation addOperation(ecore::EClassifier c, String strName, ecore::EClassifier type,  String strBody):
 setName(strName) ->
 setEType(type) ->
 eAnnotations.add(addBodyAnnotation(strBody)) ->

create ecore::EOperation addOperation(ecore::EClassifier c, String strName, ecore::EClassifier type, 
 List parameters,
 String strBody):
 setName(strName) ->
 setEType(type) ->
 parameters.collect(e|((List)e).setParameter(this)) ->
 eAnnotations.add(addBodyAnnotation(strBody)) ->

create ecore::EParameter setParameter(List parameter, ecore::EOperation op):
 setName((String)parameter.get(0)) ->
 setEType((ecore::EClassifier) parameter.get(1)) ->

create ecore::EAnnotation addBodyAnnotation(ecore::EOperation op, String strBody):
 setSource("http://www.eclipse.org/emf/2002/GenModel") ->
 this.createBody(strBody) ->

create ecore::EStringToStringMapEntry createBody(ecore::EAnnotation anno, String strBody):
 setKey("body") ->
 setValue(strBody) ->

API Changes

So far I found three API changes which required changes in my code. These changes are rather simple and briefly explained in the following.


First of all, NodeUtil.getNode(EObject); has changed. There is no type Node anymore. I had to change my code from
Node node = NodeUtil.getNode(eobj);
NodeAdapter adapter = NodeUtil.getNodeAdapter(eobj);
AbstractNode node = null;
if (adapter != null) {
 node = adapter.getParserNode();

Resources and Setup

For (JUnit) tests, I have to call a setup method in order to register Xtext's resource implementations and my model. This is now simply achieved via a generated setup method. This is the setup method I'm using now in JUnit tests:
public static void setup() {

No DSL-specific Editor Class

A little bit surprising at first is the absence of a DSL specific editor class, in my case MitraEditor. Instead, the general Xtext editor class is used, DSL specifics are injected using Google Guice as described in the Xtext manual. Most surprising is the new syntax found in the plugin.xml which is used to inject things. Here is the declaration of my editor using the new notation (the plugin.xml is generated):
<extension point="org.eclipse.ui.editors">
       name="Mitra Editor">
The attribute "class" defines the Guice module to be created and the editor class. Unfortunately I need the editor class in order to add breakpoint markers (for my debugger plugin). The old version looks like this:
public class MitraBreakpointAdapterFactory implements IAdapterFactory {
 public Object getAdapter(Object adaptableObject, Class adapterType) {
  if (adaptableObject instanceof MitraEditor) {
How do I identify the mitra editor in the new version? First of all, instead of a generated DSL specific editor, an XtextEditor is used (this class is found in plugin org.eclipse.xtext.ui.core). Then the current language can be retrieved via getLanguageName(). This is the new version:
public Object getAdapter(Object adaptableObject, Class adapterType) {
 if (adaptableObject instanceof XtextEditor) {
  XtextEditor xtextEditor = (XtextEditor) adaptableObject;
  if ("de.feu.Mitra".equals(xtextEditor.getLanguageName())) {
Note that the name of the editor class has to be changed in the plugin.xml of the debug plugin accordingly.


After applying the changes described above, my language worked as expected (at least all the tests are green and my application is running). Since I haven't written any extensions for content assist or other UI things, I only had to adjust the grammar, my M2M-transformation and the code a little bit. If you do not have an M2M-transformation, you may have to add it in order to add the missing NULL values for enumerations -- I assume this is the case quite often. TMF Xtext adds some very nice features (grammar mixings, improved linking/cross references feature with ILinkingService, serialization with formatter, return types, and tree rewrite actions). These features will simplify my hand written code immensely, and I'm looking forward using them. Last but not least, since Xtext is now part of the Eclipse modeling package, it is much easier to install an Xtext based DSL and editor. Last but not least: Kudos to the Xtext team! The new version looks really nice! And many thanks for the great and fast (newsgroup) support!

Friday, April 17, 2009

First Steps Towards a Multi Editor 3D

Some days ago I 3d-fied the UML 2 Tools Diagram Editors. Well, a single 2D editor in 3D is funny but not really thrilling. You may ask: "Why should I use a 2D editor in 3D?" And I agree with you. The idea behind GEF3D is to enable multi model or multi diagram editing (this is why I started the GEF3D project). I strongly believe that "raising the level of abstraction" as promoted by all these model-driven approaches requires good tools. What does "good" mean in that context? Many models are edited graphically*, and using different levels of abstraction means using different models, that is diagrams. Also, using different (architectural) view points means using different models or diagrams. And all these models are somehow related! But these relationships usually aren't visualized. Too often, the best thing you get is a (EMF generated) tree editor. The GMF mapping editor is a typical example. IMHO a good tool would be a tool enabling graphical notations throughout the development process. And this is what GEF3D is all about. By 3d-fying existing GEF or GMF based editors, it is possible to reuse existing code and, from the user's perspective, existing and well-known graphical notations. This is also a principle of GEF3D: Enable exiting editors to be reused in 3D. Nobody wants to write new 3D-enabled editors when there are 2D editors already available, and no user wants to learn a new 3D-like notion of the UML. The next step is to open several 2D diagrams in a single 3D scene. Actually this is working for quite some time, an example application is published in [1]. This application was more a design study or proof of concept, I 3d-fied an elder version of the TOPCASED UML editor (which is GEF based). With the 3d-fied UML2 Tools editors, I was optimistic to create a UML Tools multi editor as well. Frankly, I was very much surprised how easy that was! The example code is part of the UML2 tools example found in the GEF3D SVN. I created a video demonstrating the multi editor. Have fun! (Sorry for the bad quality, it's my first video I uploaded to YouTube) Watch the video at YouTube A multi editor certainly is only the foundation for real-world (MDD) applications. Opening multiple editors in a single 3D scene enables the visualization of inter-model (or inter-diagram) relations such as transformation traces [1], inter-package dependencies, model-differences, manual mappings and so on. While the demo sounds promising, there are a lot of problems and known bugs I don't want to keep secret. There are some problems with feedback figures, text editing is not working as expected, there are problems with rotated planes (yes, actually the planes can be positioned every where in the 3D scene), currently it isn't possible to simply move an element from one diagram to another and so on. The example is only the first step, and we are working for solving the known issues.
J. v. Pilgrim and B. Vanhooff and I. Schulz-Gerlach and Y. Berbers: Constructing and Visualizing Transformation Chains. In: ECMDA-FA 2008, Berlin, Germany, June 9-13, Proceedings, LNCS 5095, pp 17--32, Springer-Verlag, 2008. URL: http://dx.doi.org/10.1007/978-3-540-69100-6_2

*For non-graphical models, XText is a wonderful tool. Combining text and graphical models certainly is a challenge for future research ;-)

Wednesday, April 8, 2009

You will be 3d-fied. Resistance is futile.

I admit it: I like Startrek. This is why I called a special pattern used to adopt editors for using them in a 3D scene with GEF3D "Borg-Factory-Pattern" (a borg factory modifies an object after it has been created by a "normal" factory using assimilators). Kristian Duske recently "3d-fied" the Ecore Diagram Editor---but he did not use the borg factory. So, why didn't we need the borg technology to assimilate this editor to be used in a 3D scene? The Ecore Diagram Editor is based on GMF. Frankly, I have lots of respect for GMF. I know GEF pretty well, but GMF with its thousands of new extension points, policies and stuff... it's like... like.. yeah, it's like a Borg cube. The good thing about that is that borg technology is already on board. We beamed Kristian on board of that cube, and he returned with a some nice providers enabling us to add 3D-behaviour to existing GMF editors. GEF3D needed some more examples anyway, so we 3d-fied the Ecore editor, and some of the UML editors of the UML Tools (which are also GMF-based), viz. the class, activity, and use case editors. The best thing: We only had to write a bunch of classes. For example, the 3D UML class editor plugin consists of 8 classes with only 212 statements (measured by c_count). The 3D versions of these editors are available from GEF3D's SVN repository (plugins org.eclipse.gefd.examples.uml and org.eclipse.gefd.examples.ecore). To give you an impression about what you need to 3d-fy an existing 3D GMF-based editor, here is a brief description on how we adopted the UML class editor (a tutorial about GEF3D is planned for June, since then don't hesitate to post your questions in the GEF3D newsgroup!):
  1. First, a new plugin is created, with a UMLDiagram3DPlugin activator, which is not really needed.
  2. A new editor class UMLDiagramEditor3D subclasses the original UMLDiagramEditor. Instead of a 2D viewer we have to instantiate a 3D viewer, actually, this need the most code since we have to copy and paste some code from the base classes.
  3. Only one editpart and figure have to be exchanged, that is the pair for the diagram, here the package. We have to provide new 3D versions for these two classes (PackageEditPart3D, DiagramFigure3D).
  4. The new edit part has to be created by a new factory UMLEditPartFactory3D, which subclasses the original UMLEditPartFactory
  5. This factory has to be injected into the editor somehow. This is done using a GMF provider UMLEditPartProvider3D. Since we only need this provider for our 3D editor, we have added a very dirty hack to identify which editor calls the provider. This is hack is really dirty (better not look at the provider ;-) ), and I hope to find a better solution.
  6. Finally we have to exchange the policy which creates the 2D feedback handles and replace it with a 3D version. Again, this is done by a provider called UMLEditPolicyProvider3D, the 3D policy is called Handles3DEditPolicy
That's it. And what do you get for that? The result is an UML editor with the diagram projected on a plane in a 3D scene. You can use the camera to orbit and move around. Since it's derived from the original 2D UML editor, it is (more ore less) fully editable. Try to select classes and move them around, create new classes and so on. You can even open the very same UML model in the 3D editor and 2D editor simultaneously, changes are reflected in both editors automatically!
The 3D version of the UML Tool's activity diagram editor. The 3D version of the UML Tool's activity diagram editor (on the right hand side, 2D version on the left). Note the 3D handles and the transparent feedback figure!
Unfortunately there are some open issues which restrict the 3D editor: no edges can be drawn (sometimes, you can draw edges but don't see any feedback, sometimes the Eclipse IDE crashes when you try to do that). You cannot open more then one 3D editor at a time, we have a problem with the texture manager. And there are some other bugs... So many bugs? Yes, but only a very few lines of code to 3d-fy an editor. So, 3D-fy your editor and help us fixing the bugs! You may ask, huh, that's great, but why should I want to 3d-fy my editor? Well, I can think of many use cases: display multiple diagrams within one 3D scene and draw inter-diagram connections, annotate your diagrams with 3D elements (e.g. metrics drawn as 3D bars on top of classes), exchange some of your 2D figures and provide real 3D editors...

Wednesday, March 25, 2009

Waiting for "Accelerated 3D on the Web"

Yesterday, the Khronos group published a press release entitled "Khronos Launches Initiative to Create Open Royalty Free Standard for Accelerated 3D on the Web". That sounds like a candidate for enabling GEF3D editors within Eclipse RAP applications :-D The project sounds a little bit like Canvas 3D. With the X3D exporter, we learned that it is possible to use renderes other than OpenGL/LWJGL. But I'm not an Ajax expert, so I'm not sure how interactive 3D could be possible in that context. But it's nice to have visions ;-)

Tuesday, March 17, 2009

GEF3D goes X3D

Due to problems of getting LWJGL IP approved, we were wondering how to address this problem. We didn't want to fall into the same trap again, so we thought about how to reduce GEF3D's dependencies from a specific rendering library. The problem was not trivial at all, so I decided to give it to a student, Matthias Thiele. He should analyze GEF3D and its dependencies to the currently used rendering library LWJGL in the context of a bachelor thesis. The idea was to refactor GEF3D (i.e. Draw3D) in order to minimize dependencies and to create a generic renderer interface. Making renderers plugable leads to the idea of using renderers not only for drawing on the screen, but for exporting or printing, too. So besides the refactoring, a new renderer should be implemented... GEF provides several export formats, for example SVG for exchanging diagrams in a vector based file format. What SVG is for 2D diagrams, X3D is for 3D ones. So, besides the existing LWJGL-based renderer, Matthias implemented an X3D renderer. And Matthias did a great job! Based on his analysis of the GEF3D and Draw3D code, using cool tools like InferType (see intoJ project), we (that is Kristian, Matthias and myself) created a new design for Draw3D's rendering parts and we introduced an extension point to make renderers plugable! Matthias did most of the refactoring, actually before GEF3D was submitted to Eclipse. On the way we had to fix some bugs related to this (e.g. a 3D position problem or a dispose problem), but eventually it seems to work fine. Matthias wrote the X3D renderer, and he has contributed the code today. It is not available in the SVN yet, since we have to get it IP approved, first. Here you can see the result of the X3D export: The original GEF3D diagram is shown at the bottom left. The large diagram is the very same image, exported as X3D and viewed with the instantplayer. The small image on the top left shows the very same X3D file, this time rendered with the Octaga Player. The current version of the X3D exporter is only a beginning. We certainly have to improve the quality of the diagrams, but it shows what is possible. Maybe other programmers write other cool renderers for GEF3D in the future ;-)

Friday, February 13, 2009

Unbelievable: Cooler than GEF3D ;-)

With GEF3D you can produce nice 3D diagrams. Of course, GEF3D is not the only framework which can produce 3D diagrams. An australien colleague, Paul McIntosh, uses X3D (the VRML successor) to create nice 3D UML diagrams, quite similar to the diagrams created with GEF3D. If you have thought, GEF3D's 3D diagrams are cool, well, then have a look at Paul's latest project. He combines his diagram with augmented reality: Watch the video at YouTube Just to get it right: This is not GEF3D, but Paul's X3D-UML! This is amazing, isn't it. Jin, Paul -- great work! (Uh... don't you want to port this to GEF3D? ;-) ) If you want to see more of Paul's work, visit his website: http://www.x3d-uml.org/

Wednesday, January 14, 2009

GEF3D committed into SVN

After getting the preliminary approval I've just committed the initial GEF3D contribution into the SVN (GEF3D is participating in the parallel IP process). You can now check out GEF3D from svn://dev.eclipse.org/svnroot/technology/org.eclipse.gef3d In order to test GEF3D, you'll need the following projects (please add org.eclipse to the name): draw3d, draw3d.geometry, gef3d, gef3d.ext, gef3d.gmf, and gef3d.examples.graph Optionally you can check out the test and documentation projects, however there are currently not much tests and documentation available (but you can use the ant script in doc in order to generate the JavaDoc). Draw3D, the 3D version of Draw2D, needs a renderer module in order to produce any output. Currently, only LWJGL is supported (or.eclipse.draw3d.lwjgl). The module only contains the Draw3D specific code, additionally you will need the LWJGL libraries. These are available via the LWJGL update site at http://lwjgl.org/update. An description can be found at http://www.fernuni-hagen.de/se/personen/pilgrim/gef3d/lwjgl.html. The GEF3D example is running, but there is a known bug. We are working on that already... Actually there are more bugs known, we will add them to Bugzilla as soon as possible ;-) After checking out all these projects, the example editor can be activated by simply creating a file with appropriate extension: ".graphSample" for the 3D editor, ".graphSampleDia" for a 2.5D editor (i.e. 2D figures projected on 3D planes), and ".multiGraphSample" for a multi plane editor. Update: The current installation instruction can be found at http://wiki.eclipse.org/GEF3D.