Tuesday, February 8, 2011

Extract Xtext Project Wizard

Besides a nice parser and a powerful editor, Xtext can also generate a project wizard and a generator plugin. In this little posting I will explain how to extract the project wizard related code from the generated UI plugin -- and explain why you would want to to that in the first place. First of all, what does the project wizard? The project wizard is useful to set up an initial project for your DSL, e.g., for creating initial templates, workflow files and to configure the project and its dependencies. The nice thing about the Xtext generated wizard is, that the template files are simply created using Xpand. It is very easy to provide custom templates and other stuff by simply modifying the Xpand file. You will find that Xpand template in the UI plugin, if you have enabled the wizard fragment in your DSL generator workflow:
// project wizard (optional)
fragment = projectWizard.SimpleProjectWizardFragment {
 generatorProjectName = "${projectName}.generator"
 modelFileExtension = file.extensions
}
This code is uncommented by default. So, Xtext generates a nice project wizard. This project wizard is found in the generated ui project. Let's say, my language is called sample.mydsl, then the wizard is created in sample.mydsl.ui, together with the powerful editor. Now, why would I want to extract this editor from the ui plugin. Actually, because I want to use the wizard during development of my language. Sounds silly... OK, here is the longer explanation: I find the wizard extremely useful especially if I have a project which uses code generation. Although you can use any kind of code generation technologies, you probably will often use Xpand and Xtend, as it is nicely integrated with Xtext. That is, Xtext can also generate a generator plugin with some template files and most notably a workflow file (MWE2). Actually, the generated generator plugin looks almost similar to a plugin project created by the generated project wizard. That is, both, the generator plugin and a project wizard created DSL project, contain a folder src/model with a sample model, and also a sample MWE2 generator file. Also, both projects contain a src-gen folder, and the plugin-dependencies are set accordingly. This is no coincidence: If you use code generation for your DSL, and if you use Xpand to perform the generation, using an MWE2 workflow to trigger the generation is a very easy solution. Alternatively, you will have to write a new action or something, but the MWE2 workflow is much easier to set up. The model provided in the generator plugin is usually only used for testing purposes. That is, you write your Xpand (and Xtend) templates in the generator plugin and you can quickly test them by applying them on the models provided in the generator model folder. Later, when the generator plugin is installed, the user of the generator won't see the Xpand templates in the workspace, however they can be accessed by the MWE2 workflow of the DSL project. During development, you probably run into the same situation as I did: You write the templates, then some things are changed in your DSL and you have do adjust the templates, or new features should be implemented, or you have forgotten some weird constellations, or you haven't written templates for all model elements. Most important: You probably will have several different models and you do not want to get the generated code to be generated in your generator plugin (as it should only define the templates, and should not contain some weird generated Java or whatever files). In my case, other guys on the project write the DSLs and I have to maintain the templates. I rarely use the generated DSL editor myself, but I often have to use the generator (and adjust the templates). Since I needed an extra project for each different case, I found myself copying the generator plugin (without the templates, but with my nicely configured MWE2 workflow) over and over again. I always had to adjust the plugin dependencies and so on. Well, a wizard would be nice in that situation. Now, you see my point? The Xtext generated project wizard is exactly what I needed -- but I need it in an Eclipse instance in which I do not have my DSL editor (and neither the DSL parser) installed, as this is the very instance I develop these things. But the wizard would come quite comfortably. So, the idea is as follows: I extracted the wizard into a separate plugin. The wizard plugin has no dependencies to my DSL, so it can be installed without my DSL plugins installed. However, the generator, i.e. the MWE2 workflow, requires all my DSL stuff. But this is no problem, as the generator plugin is an opened project in my development workspace -- thus the MWE2 workflow (not the plugin code, but the workflow) can access the project. Here is how to extract the project wizard (which is not too complicated, however it may save you some minutes):
assumption
You have an existing Xtext project, I will call it "sample.mydsl" in the following, and, of course, a generator plugin "sample.mydsl.generator" created for your DSL. Inside the generator, you have configure the MWE2 workflow.
generate project wizard
Enable Project Wizard Fragment in your DSL workflow, e.g. in "GenerateMyDSL.mwe2" of your DSL project:
// project wizard (optional) 
fragment = projectWizard.SimpleProjectWizardFragment {
 generatorProjectName = "${projectName}.generator" 
 modelFileExtension = file.extensions
}
Now run the workflow "GenerateMyDSL.mwe2", and disable the project wizard fragment (as we do not want to have two wizards in the end).
create wizard plugin
Create new plugin project (e.g., sample.mydsl.ui.wizard) with and Activator, check "This plugin-in will make contributions to the UI".
Important: Use "sample.ui.wizard" as package for the Activator (without mydsl), in order to retrieve the same package names as in the Xtext generated ui project.
move wizard code to new plugin
Move the following classes from the generated ui plugin into the wizard -- this is the actual "extraction" of the wizard:
from src-gen:
  • sample.ui.wizard.MyDSLNewProjectWizard
  • sample.ui.wizard.MyDSLProjectCreator
from src:
  • sample.ui.wizard.MyDSLProjectInfo
  • sample.ui.wizard.MyDSLNewProject.xpt
and copy the following classes from the generated ui plugin into the wizard plugin, put them into the wizard package:
  • sample.ui.MyDSLUiModule
from src-gen:
  • sample.ui.MyDSLExecutableExtensionFactory
Also copy the plugin from the ui plugin into the wizard plugin and remove everything except the last extension with point "org.eclipse.ui.newWizards", adjust class name of extension factory according to the class in your wizard project (you will have to add a ".wizard" to the fully qualified name).
configure wizard project
In Manifest, set singleton directive to true (if not already set) and add missing plug dependencies, e.g.
  
 org.eclipse.xtext.ui,
 org.eclipse.ui.editors;bundle-version="3.5.0",
 org.eclipse.ui.ide;bundle-version="3.5.0",
 org.eclipse.xtext.ui.shared,
 org.eclipse.ui,
 org.eclipse.xtext.builder,
 org.antlr.runtime,
 org.eclipse.core.runtime,
 org.eclipse.core.resources,
 org.eclipse.xtend,
 org.eclipse.xpand
Depending on your project, you may have to add other dependencies as well, e.g. de.itemis.xtext.typesystem if you use the great Xtext type system by Markus Völter.
adjust the copied and moved java files
  • MyDSLUiModule is to be replaced completely:
     
     public class MyDSLUiModule extends AbstractGenericModule {
     
     private AbstractUIPlugin plugin;
    
    
     public MyDSLUiModule(AbstractUIPlugin plugin) {
      this.plugin = plugin;
     }
     
     public void configureLanguageName(Binder binder) {
      binder.bind(String.class).annotatedWith(Names.named(Constants.LANGUAGE_NAME)).toInstance("sample.MyDSL");
     }
     
     public void configureFileExtensions(Binder binder) {
      binder.bind(String.class).annotatedWith(Names.named(Constants.FILE_EXTENSIONS)).toInstance("MyDSL");
     }
     
     @Override
     public void configure(Binder binder) {
      super.configure(binder);
      binder.bind(AbstractUIPlugin.class).toInstance(plugin);
      binder.bind(IDialogSettings.class).toInstance(plugin.getDialogSettings());
     }
     
     
     // contributed by org.eclipse.xtext.ui.generator.projectWizard.SimpleProjectWizardFragment
     public Class<? extends org.eclipse.xtext.ui.wizard.IProjectCreator> bindIProjectCreator() {
      return MyDSLProjectCreator.class;
     }
    }
    
  • MyDSLProjectCreator can be reused, however you may want to add some dependencies to the getRequiredBundles method, depending on the dependencies of your generated classes:
      
    @Override
    protected List<String> getRequiredBundles() {
     List<String> result = Lists.newArrayList(super.getRequiredBundles());
     result.add(DSL_GENERATOR_PROJECT_NAME);
     result.add("org.eclipse.jface.text");
     result.add("org.eclipse.jdt.core");
     result.add("org.eclipse.equinox.common");
     result.add("org.eclipse.core.runtime");
     return result;
    }    
    
    Actually, this list is the list of required bundles of your generated code. That is, if you generate Java code which requires a plugin "my.super.plugin", you have to add the dependency here.
  • MyDSLNewProjectWizard: you probably have to fix a problem in getProjectInfo, simply change the fully qualified name MyDSLProjectInfo to a simple name, as we have moved the info into the same package.
  • MyDSLExecutableExtensionFactor: fix class name of plugin activator, change getInstance().getInjector("..") to getDefault().getInjector()
  • Activator: Add initialization of Guice injector and add an injector attribute to the wizard's activator:
      
    public class Activator extends AbstractUIPlugin {
        ..
        Injector injector;
    
     public Injector getInjector() {
      return injector;
     }
    
     @Override
     public void start(BundleContext context) throws Exception {
      super.start(context);
      plugin = this;
    
      injector = Guice.createInjector(
      // Wizard:
       Modules.override(new MyDSLUiModule(this))
       // Workspace etc.:
        .with(new org.eclipse.xtext.ui.shared.SharedStateModule()));
    
     }
     ..
    }
    
remove obsolte code from ui plugin
  • remove method bindIProjectCreator in AbstractMyDSLUiModule
  • remove the wizard extension point definition from the ui plugin.xml, as you probably do not want to have two wizards.
You can now run the wizard in the Eclipse runtime (i.e. the Eclipse started from within your initial, vanilla, installation). Of course, you can modify the Xpand template, e.g. I have simply copied and pasted the workflow of my generator plugin into that Xpand file. You may also add other adjustments as well. Now, you can export the wizard as a plugin and install it to the dropins folder of your Eclipse installation. After restarting that instance, the wizard is available in the workspace in which you develop your DSL. As it has no dependencies to the DSL, you can create new projects, which are configure as you specified above. The workflow is working, although it probably has dependencies to your DSL (e.g., it uses the generated DSL parser), at the DSL project is an opened project in your workspace. Side effect: Actually, you have extracted the Guice infrastructure as it is used by Xtext generated editors. So, even if you do not use your wizard as often as expected, you may have learned some stuff about this better-then-factory-pattern technology.

Friday, January 21, 2011

Clickable logging messages

Probably everyone is using logging. The dirty way is to use System.out/err, a better solution is to use the JDK logging or some logging library, such as log4j (or a facade, e.g., slf4j) -- and of course Log4E to generate the logger declaration and other logging code . For rich clients and small tools, I usually use the JDK logging, as I do not have to add another library and the logging is only used for development purposes. For web (or other server) applications, in which logging is an important monitoring tool, other log libraries may be a better choice. Anyway, when using the JDK logging facilities, the log message is written to the Eclipse console view by default. A simple log message usually looks like that:
Jan 14, 2011 4:36:54 PM my.project.MyClass bar
INFO: Demo
This is ok, however I usually do not need the date and time. Also, IMHO two lines for a single message waste too much of my console view space. I have written a small formatter, which produces the following output (scroll to the right to see the whole ouput):
I Demo                     at my.project.MyClass.bar(MyClass.java:88)
That is, the date and time is omitted (as this usually is not needed for development purposes), and instead of printing the full logging level, abbreviations are used (I - info,W - Warning, S - Severe and so on). In case of shorter messages, the location information is printed on the same line with some tabs between message and location for better readability. The best thing about that format is, that the Eclipse console recognizes the location and makes it available as a link, which directly opens the location in the source code where the log message was produced. If you configure the console preferences to use gray for standard error text (as which the log message is interpreted due to the location format), you will something like that:
W Test Warning             at my.project.LoggingTest.main(LoggingTest.java:32)
I Test Info                at my.project.LoggingTest.main(LoggingTest.java:36)
Actually, I'm using this formatter for quite some years now. Today I have created an eclipselabs.org project called delofo (short for Developer Logging Formatter) with this formatter. I've chosen eclipselabs.org because the formatter is optimized for the Eclipse console view, although the project does not provide a plugin and can be used w/o Eclipse. In the project wiki, you will find an installation guide, explaining how to globally install the formatter. By installing the formatter globally, you do not have to modify your projects in anyway.

Tuesday, June 1, 2010

Install strictly J2SE-1.4 compatible JRE on Mac OS X Snow Leopard

Today I tried to compile a project requiring J2SE-1.4, i.e. with
Bundle-RequiredExecutionEnvironment: J2SE-1.4
specified in its manifest. On OS X 10.6, JRE 1.4 is no longer installed, instead, version 1.4 points to 1.6. Unfortunately, this JRE is not strictly compatible to J2SE-1.4, as I have learned from this error message:
Build path specifies execution environment J2SE-1.4. 
There are no JREs installed in the workspace that are 
strictly compatible with this environment.
Simply making a selection on the 1.6 JVM in the list compatible JREs in Preferences / Java / Installed JREs / Execution Environment / J2SE-1.4 doesn't help (I tried to clean the projects, but 1.6 is not strictly compatible, thus clean doesn't help here). So, I had to install JDK 1.4, which probably is no problem for Windows and Linux users. However, on OS X, you'll have to follow the hints explained at www.macosxhints.com and repeated here for your convenience:
  1. Remove symbolic links in /System/Library/Frameworks/JavaVM.framework/Versions/ pointing from 1.4.* to 1.6 (otherwise, the 1.6 JDK will be overwritten). E.g, in the terminal (with admin rights):
    > cd /System/Library/Frameworks/JavaVM.framework/Versions/
    > sudo rm 1.4*
  2. Download http://support.apple.com/downloads/Java_for_Mac_OS_X_10_5_Update_4. Yeah, it is still available, but Apple doesn't make live easy for Java developers these days: Do not install this package (as it will overwrite your existing Java versions)! See next step instead
  3. Open downloaded pkg with Pacifist (http://www.charlessoft.com/).
  4. Select JDK 1.4 and 1.4.2, and install it to default location via Pacifist's context menu (see screenshot)
Now, JDK 1.4 is installed on OS X 10.6. We only have to let Eclipse (in my case 3.6RC1) know about it: In Eclipse, select Preferences / Java / Installed JREs / Add Standard VM Enter JRE Home: /System/Library/Frameworks/JavaVM.framework/Versions/1.4.2/Home and JRE Name: JVM 1.4 (or whatever) You will have to close Preferences (OK), and reopen it in order to let the newly added JRE to be added to the list of compatible JREs. In Preferences / Java / Installed JREs / Execution Environments / J2SE-1.4 select JVM 1.4 (now marked with "perfect match") in list of compatible JREs. That's it. Ted Wise provides zipped versions of JVM 1.5 and 1.4, and you may install these versions following his description at http://tedwise.com/2009/09/25/using-java-1-5-and-java-1-4-on-snow-leopard/. In that case, you won't need Pacifist.

Saturday, March 20, 2010

Quick test: GEF3D and e4 1.0 M4

Yesterday I posted my experiences of getting GEF3D running on e4 0.9. This is only a quick update for e4 1.0 M4. Remy Chi Jian Suen pointed me to e4 1.0 M4, and I followed the instruction on the Wiki page Remy linked to. Unfortunately, I did not succeed installing GMF with e4 1.0 M4 because there were always some unsatisfy dependencies errors. So I wasn't able to reproduce the NPE I described in the blog, and I wasn't able to test the Ecore Tools 3D example. I'm not personally using e4, so at the moment getting GEF3D running on e4 is not my first priority and I didn't investigate any further. Besides, I got a lot of exceptions in the e4 runtime, after restarting the runtime several times it didn't started at all. I get tons of "!MESSAGE unsupported:" messages, and when trying to create a new project with the context menu, the "new"-submenu is missing, finally I get another NPE:
java.lang.NullPointerException
 at org.eclipse.ui.internal.e4.compatibility.WorkbenchPage.getNewWizardShortcuts(WorkbenchPage.java:1172)
 at org.eclipse.ui.actions.BaseNewWizardMenu.addShortcuts(BaseNewWizardMenu.java:142)
 at org.eclipse.ui.actions.NewWizardMenu.addItems(NewWizardMenu.java:129)
 at org.eclipse.ui.actions.BaseNewWizardMenu.getContributionItems(BaseNewWizardMenu.java:205)
...
I don't know how but after switching the perspective I was able to create at least a simple project, and then the new-submenu was available enabling me to create a GEF3D graph example. So I got GEF3D to run with 1.0 M4 (proofed by screenshot ;-) ), however I found a severe problem with GEF 3.6 and I filed a bug report about that (# 306609). I had to fix that in order to get GEF3D running. Actually, this problem is a GEF3D blocker and I really hope the GEF team can solve that issue. As a matter of fact I'm glad to have found that bug now. I hope it's not too late for the final 3.6 version.
GEF3D on e4 1.0M4! Do you see the level-of-detail effect , i.e. labels on back planes are omitted! (Again kudos to Kristian ;-) )
Boris asked me to file a bug report, but frankly I don't know where to start... I could create a bug report about the NPE I described in my previous post, but I'd assume 0.9 is a little bit out-dated, isn't it?

Friday, March 19, 2010

Quick test: GEF3D and e4

Today I received an email from someone asking whether GEF3D will work with e4. Since GEF3D is "only" an extension of GEF (and GMF), I assumed it will work. In order to be sure, I tried it myself. This is my installation log: Step 1) Downloaded the e4 0.9 release (http://download.eclipse.org/e4/downloads/drops/R-0.9-200907291930/index.html#EclipseE4), in my case the Mac OS X Cocoa version Step 2) Installed the following features via the given update sites: Step 3) Imported GEF3D team project set found at http://eclipse.org/gef3d/resources/GEF3D.psf State: The 3D graph example is working, see screenshot.
GEF3D on e4! (Note the nice vector based fonts :-D Kudos to Kristian!)
Step 4) Now installed the missing features in order to test all examples: Restarted e4 after downloading these bundles. Ups, what's that? My toolbar has gone...? Where is it? However, I doubt GEF3D or GMF to be involved in that bug... Hmm... was there a toolbar before step 4)? Weird. UML2 Tools and Ecore Tools are working, at least the 2D versions. Unfortunately, the 3D versions are not working. There are not much error messages:
java.lang.NullPointerException
at org.eclipse.e4.extensions.LegacyPartRenderer.createEditor(LegacyPartRenderer.java:95)
at org.eclipse.e4.extensions.LegacyPartRenderer.createWidget(LegacyPartRenderer.java:357)
...
I didn't analyzed that error... without a toolbar, it's not very comfortable. Besides, I didn't found the code of LegacyPartRenderer and I didn't find a way to declare an exception breakpoint. Summary: Since the 3D graph example is working, I assume GEF3D and e4 should work in general (e4 does change the workbench, but not SWT or GEF). However, the 3D-fied UML2 and Ecore editors are not working, but I have no idea why they don't. Maybe it's not e4 but a problem with the latest GMF or ecore tools versions, I don't know. Frankly, I have ignored e4 for the time being (simply because I haven't had the time). IMHO you cannot simply install existing 3.x plugins and expect them to work with a 0.9 incubator framework. In so far I'm happy about the 3D graph example running! Besides, I assume my test only tested the legacy layer of e4, and not e4 itself. However, I'm still wondering why the 2D version of the ecore diagram editor is working and why the 3D version isn't. I'd assume there exist documents in the e4 project about how to solve problems like this.

Tuesday, January 19, 2010

Quick'n Dirty Tutorial on Modelling with Eclipse

A friend of mine asked me how to modelling with Eclipse. I gave him a quick tour, demonstrating how to create a model with EMF, how to create an instance of that model, how to query the model with OCL, and how to create a text editor for that model with Xtext. It's pure modelling, i.e. no Java programming at all! I thought that maybe other people would be interested in that topic as well, so I created this little tutorial showing how all these Eclipse modelling "ingredients" can work together.

Preparations

Install Eclipse 3.5 (Galileo) with all the modelling tools, that is the Galileo Eclipse Modeling Tools package. Additionally, we will need the OCL interpreter console, which can be installed using the MDT update site:
http://download.eclipse.org/modeling/mdt/updates/releases/
The OCL console actually is an example, so you will have to install that specific example.

The Runtime Example

Let's assume a small IT company. The employees of that company develop software for other companies. Of course, they use models for that purpose! In order to better organize their work, they want to document who is working on what. That is, they want to assign certain task to developers. A task could be the implementation of a use case or writing a test case for a class. Let's see if we can use models for that...

Company Model with EMF

First of all, we have to create a model describing the company. Let's start from scratch:
  1. create a new project:
    File / New / Project... / Eclipse Modeling Framework /Empty EMF project
  2. create a new ecore diagram (we want to graphically design the model) in the newly created model folder: Right click on model folder and select
    New / Other... / Ecore Tools / Ecore Diagram
  3. enter the Domain file name:: company.ecore and press Finish.
Now, we can "draw" our model using the graphical editor. Create four classes (EClass), add a name attribute (EAttribute) to one of them, create references (EReference) between the classes, and set the properties (in the properties view, this view can be activated by right-clicking in the diagram and select Show Properties View. The result should look like Figure 1.
Figure 1: The domain model of a company
Some remarks:
  • The model is an instance of the ecore model, which is quite similar to class models in UML. All elements in ecore start with an "E", so it is EClass, EAttribute, or EString.
  • The EType of the attribute name is EString.
  • The upper bound of all references is "*" (you can enter "-1", which actually is the same as "*").
  • You will need a class containing all your elements later. In the example, the Company serves as a container. Make sure the Is Containment flag is set for the two references employees and skills (see Fig. 1)
Now that we have created a model of our company, we can create an instance of that model. Later, we will generate an editor, but right now we want to quickly create an instance to get a feeling for our model. An instance of our model actually is an instance of our container element, that is the Company class. There is a generic editor available, which can create an instance of a model (or its elements) directly without the need of code generation. All you need is the ecore model. This is how to activate it:
  1. Close the ecore diagram
  2. Open the ecore model, this time use the Sample Ecore Model Editor. Usually, this editor is used if you double-click the ecore-file, but to be sure use the Open With... context menu entry.
  3. Select the Company class (the class, not the package!), and select Create Dynamic Instance... from its context menu. This is shown in Figure 2.
    Figure 2: Create a dynamic instance.
  4. enter the File name: Company.xmi and press Finish. The instance will be created in the model folder.
  5. edit the model instance using the context menus New Child of the elements in the model.
  6. edit the elements properties in the properties section of the editor, see Figure 3.
    Figure 3: Edit properties with the Generic EMF Form Editor
Now that we have create a model and an instance of that model, we want to "work" with that model instance. E.g., we can use OCL to query the model:
  1. Activate the console view and open the Interactive OCL console with the button on the left of the console, see Figure 4.
    Figure 4: Open OCL interpreter console
  2. Select an element in the editor, This selected element is the context of the OCL query.
  3. Enter your OCL query in the console (in the lower section of the OCL interpreter console). E.g. query the name of the selected element with self.name. The result will be displayed in the upper section of the OCL console as shown in Figure 5. We will demonstrate other queries later on.
    Figure 5: Query the model instance with OCL

Task Model with Xtext

Now that we have a model of our company, we want to assign tasks to the employees. We could create a new ecore model just as demonstrated above, but we want to try something new. So, let's try to not only create a model, but a text editor as well. For that, we will use Xtext. Based on a grammar, Xtext can create an ecore model and a text editor with nice features. The grammar is an annotated EBNF grammar, I do not want to go into the details here (otherwise it wouldn't be a q'n d-tutorial ;-) ). So, we have to create a new project and enter a grammar:
  1. Create a new Xtext project:
    File / New / Project... / Xtext /Xtext Project
  2. SetMain project name, the Language name (to de.feu.Tasks), and the DSL-File extension (to tasks).
  3. Open Tasks.xtext (this is the EBNF-like grammar) and enter your grammar according to Figure 6.
    Figure 6: Xtext grammar defining our task model along with a concrete textual syntax
    Here is the grammer (for copy & paste):
    grammar de.feu.Tasks with org.eclipse.xtext.common.Terminals
    
    import "http://www.eclipse.org/emf/2002/Ecore" as ecore
    import "platform:/resource/de.feu.company/model/company.ecore" as company
    
    generate tasks "http://www.feu.de/Tasks"
    
    Tasks :
     (developers+=Developers)*
     (domainmodels+=DomainModels)*
     (tasks+=Task)*;
     
    Developers :
     'developer' importURI=STRING;
     
    DomainModels :
     'domainmodel' importURI=STRING;
    
    
    Task: 'task' element=[ecore::EObject] 
       'by' developer=[company::Developer] 
       ':' description=STRING;
    
    This grammar defines a container element Tasks. Inside, we can "load" a list of developers and domain models. Eventually, tasks can be defined by assigning an element from a domain model (see element=[ecore::EObject]) to a developer (developer=[company::Developer]) and add a description of that task.
  4. Save the gammar and generate the ecore model along with the text editor using the MWE-workflow. For that, select file GenerateTasks.mwe and run the workflow via its context menu Run As / MWE Workflow
Notes:
  • In Xtext, a model is called a DSL. Experts like to use different names for "model", sometimes it's cooler to call a model "meta-model" (or, even cooler, "meta-meta-model"), sometimes they call it "domain specific language", abbreviated with a nice TLA (three letter acronym): DSL. Of course, there are good (and sometimes not so good) reasons for doing so, but usually it's easier to simply call a model a model (and an "instance of a model" an "instance of a model") .
  • The grammar shown in Figure 6 actually uses a lot of nice Xtext features and you will have to read the Xtext documentation for details. I only want to explain one thing here, which is a little bit advanced. You can import existing models into the grammar (import ...). In the example, we import the ecore model and our previously created company model. We import these models in order to be able to define inter-model references later on. Our Task element will refer to an element, which can be any ecore::EObject, and the developer is to one developer defined in our company model (company::Developer). EMF supports inter-model-references, and Xtext generated editors support that feature as well! The import statements in our grammar only import the models, but later on we want to actually import existing model instances. For that, we need the importURI feature of Xtext to define what instance to import in our actual task model instance.
Although we haven't written a single line of Java code yet, a lot of code has been generated automatically. In order to "activate" that code, which actually defines a new Eclispe plugin, we have to start a new runtime instance of Eclipse, that is we start Eclipse from within Eclipse. In the long run, you will have to get used to Eclipse plugin development anyway... As we have to run a new instance anyway, we can generate an editor for our company model as well. Instead of using a dynamically created instance using the "Generic EMF Form Editor", EMF can generate a Java implementation of the model and an editor as well. We will do that now:
  1. Select the company.ecore file and choose New / Other... / Eclipse Modeling Framework / EMF Generator Model from its context menu. Use the suggested file name, select Ecore Model in the next wizard page. Then, press Load in the next page, and eventually Finish on the last wizard page. This creates a generator model, which basically adds some information to the original ecore model which is necessary in order to actually generate code (e.g., the name of the plugins and so on). We do not want to change anything here, but we still need that model.
  2. In that model, select the very first element (Company) and select Generate All from its context menu (see Figure 7).
    Figure 7 Generate the model and editor code

Work with Multiple Models

Now that we have generate a lot of code, we want to use the newly created tools. Start a new Eclipse runtime instance (e.g. by selecting Run As / Eclipse Application from a project context menu) and do the following:
  1. Create a new project (in the runtime instance):
    File / New / Project... / General /Project
  2. Select the project and choose from its context menu:
    New / Other... / Example EMF Model Creation Wizard / Company Model
    This activates our previously generated editor (and a wizard) for creating a company model instance. We can edit a company instance just as we did it with the generic editor. In the wizard, select the Model Object Company and then create a new company as shown in Figure 8. (Don't forget to save the model ;-) ).
    Figure 8: A company model, edited with the generated editor
  3. Now, create a new file (File / New / File) inside the project and call it project.tasks. The Xtext generated editor is opened automatically and we can now edit the task model instance.
  4. In order to "simulate" a project, we create a simple UML use case model. Simply create a new use case diagram via File / New / Other... / UML 2.1 Diagrams / Use Case Diagram, give it a name (e.g. project_usecase) and draw some use cases, a sample is shown in Figure 9.
    Figure 9: A sample use case diagram
  5. Switch back to project.tasks and "import" our company model and the sample use cases. Add a task using content assist (Ctrl-Space) just as shown in Figure 10. Just play around, add three or four tasks in order to be able to follow the next steps.
    Figure 10: Content assist, demonstrating access to imported models
  6. Just as at the beginning, we want to execute some OCL queries on our model, but this time on our project.task model instance. For OCL, we always need a context, but unfortunately we cannot select a context (or model element) in the text editor. So we have to reopen the project.task with the generic EMF editor: Choose from its context menu Open With / Other... / Generic EMF Form Editor. You will now see the very same model as in the text editor, but this time you see a tree-based version of the model.
  7. Open the OCL console just as above, select an element (here Tasks) and enter a query. For example, we want to know how much tasks are assigned to a specific developer: self.tasks->select(developer.name='Jens')->size(). You can see that in Figure 11
    Figure 11 A little more sensible OCL query

Conclusion

IMHO it is impressing what you can do with all these cool Eclipse modelling tools, without writing a single line of (Java) code. We saw how to
  • create an EMF ecore model with the Ecore Tools diagram editor
  • open the same ecore model with the Generic EMF Form Editor
  • create instances of a model without the need to generate code and without starting a new runtime instance, using the "Create Dynamic Instance" feature (and the generic EMF editor again)
  • generate a text editor and a model without a single line of Java code with Xtext
  • generate a tree based editor and a Java based model implementation with EMF
  • create a UML diagram with the UML Tools diagram editor
  • query your models with OCL from the OCL project
We didn't bothered about how to store our models or model intances (it's all XMI), we were using OMG standards like UML (the EMF based implementation is provided by the UML2 project, EMF's ecore is an EMOF-like model, we were using OCL, other implementations are available, too (e.g., BPMN2, SBVR, or SPEM used by EPF). And if you do not find an Eclipse project, you probably will find a third party project providing an EMF based implementation ;-) With tools like GEF or GMF you can create (or generate) diagram editors for your models, and (well, I couldn't resist) with GEF3D you can even create 3D diagram editors, e.g. for visualizing inter-model connections. And there are many more tools out there, partially for simplifying the use of existing tools, for model transformations and code generation and so on. And of course you can adapt and modify the code generated above to suit your need.

Warning: Thin Ice!

While it is very easy to do impressive things (with the help of a tutorial), it is very hard to get into all these frameworks and tools. There are a lot of traps hidden everywhere! Just two examples from the tutorial:
  • In the Xtext grammar we used here, the ecore model was imported (see Fig. 6). I tried the very same using the UML2 model, and I got a weird error when generating the code (actually I couldn't generate in that case).
  • A NullPointer-Exception is thrown (you can see that in the console of the original Eclipse instance) when opening the project.tasks file with the Generic EMF Form Editor. Fortunately it still is possible to select an element (for the OCL query), but it's a little bit weird.
Well, I probably should file a bug report at least for the first problem... So be warned: Even if the tutorial gives you the impression as if modelling with Eclipse tools is very easy, it sometimes isn't. In general, modifying generated code as well as using tools like GMF is not that simple. But at least there are the newgroups, tutorials, and even books (e.g. the EMF book (2nd edition!) or the GMF book).

Disclaimer

This is a quick and dirty tutorial article. I simply documented an example modelling session by taking some screenshots, and then wrote some explanations. So, there probably are some things I've missed to tell you or errors in my text. Please leave me a comment if you find a bug here ;-) (or if you like the tutorial). May the Model be with you!

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 ;-)).