woensdag 28 januari 2009

Generating dynamic web apps with DSL and GWT

The idea for my presentation at Devoxx'08 originated last summer when I attended the java event organized by ProfICT. There I saw Neal Ford build the case for Domain Specific Languages (DSL) and subsequently saw Sven Efftinge demo xText and explain how to craft your own DSL with this Eclipse based plugin called openArchitectureWare. A very interesting event and I immediately saw the potential of DSLs for one of my clients.
For this client I once built an intranet application that let their internal sales reps generate quotes for their customers selling complicated power generators. These quotes consisted of different components with many dependencies between them. Back then I created an XSLT/JSP solution which described the problem domain as well as the front end representation in one huge XML file. After attending Neal Ford's relentless XML bashing I understood that this application needed a rewrite based on a DSL.
So basically the idea was to describe the problem domain (complex power generators) in an external DSL and visualize it using a nice front end application. Out of personal interest I decided to construct the front end using Google Web Toolkit (GWT) but without writing too much code for it.
Just to verify the feasability of this idea I wrote a proof of concept for a fictitious bicycle store, looking like this:

So what did I need to build this proof of concept? Well, I needed to think about how I'd like to model my problem domain. Basically, the bicycles sold in our shop are composed of a few Entities with certain values and there are relations between these entities. Also, I wanted to be able to group the potentially long list of entities over a few steps. So I came up with a model which looked like this:

So we have two entities (Type and Color) and the values of Color depend on the Type. Example: Racing bikes are only sold in silver whereas City bikes are available in all four colors. Both entities are displayed in the one and only Step (actually in the demo above there are two steps with four entities but you get the idea)
This model was constructed according to the new DSL which I had to define in xText at the same time. xText is an eclipse plugin which offers you a wide range of tools and aids to build your own DSL, making use of the familiar context sensitive code completion features in Eclipse.
The definition of the DSL is another text file which looks like this:

Model:
(elements+=Element)* (steps+=Step)*;

Element:
"elt" name=ID "{"
((option+=Option) ("," option+=Option)*)?
"}" (dependsOn+=Reference)*;

Reference:
"dependsOn" elt=[Element] "{"
((dependency+=Dependency) ("," dependency+=Dependency)*)?
"}";

Option:
description=STRING (deflt?="default")?;

Dependency:
fromOption=Option ":" "{" ((toOption+=Option) ("," toOption+=Option)*)? "}";

Step:
"step" nr=INT label=STRING "{"
(elt+=[Element] ("," elt+=[Element])*)?
"}";


This format of this grammar description is an extension of the Backus-Naur-Form. It basically says that our Model consists of one or more Elements and one or more Steps, which in turn have their own restrictions.
With a correct grammar definition you can ask openArchitectureWare to generate a new eclipse plugin editor which enables you to actually write your model. This editor automatically contains code completion compliant to your grammer, i.e. it will display a red cross when you accidentally type Elemend instead of Element. Moreover you can expand your editor with your own rules. It might, for example, not make sense to have multiple Elements with the same name. This is not enforced by the DSL grammar but can be added to the plugin editor with the following rule:

context Element ERROR "Names of all entities must be unique." :
allElements().typeSelect(Element).select(e|e.name == this.name).size == 1;

xText/openArchitectureWare is actually quite a powerful environment, backed by an active user community. Anyway, this is all nice and interesting but what if we want to do something useful with our model? This is where xPand templates come into play. The idea now is that we will write a few templates which generate java code which, in turn, is added to a skeleton GWT application. An excerpt from one of the templates:

What this template will do is generate the source code of a java enum called Entity. In the constructor of the enum we pass in an array of possible values for the entity and a String with the default value. Two more templates were needed: one to generate an enum of the Steps and the third one to define the dependencies between the entities.

The GWT application is not much more than a StackPanel with one panel for each step. Inside these steps we render the entity values in a select boxes. These select boxes contain onChange event handlers which cause the dependent entities to be recalculated, i.e. when we change the bicycle type from City bike to Racing bike, the list of possible Colors has to be reduced from four to only one Color. This logic was built in GWT and is the same for any model we generate into the GWT application using our DSL.

So in theory it would now be possible to construct a real world application with the entire list of product entities and their dependencies in the xText editor; generate the GWT classes using the xPand templates, re-generate the GWT application and we're ready! Of course the GWT application would also have to be augmented to actually DO something with all the selections, at the moment we only allow to the user to click through the different options without actually doing something (i.e. ordering a Green Citybike).

By the way, I think the power of GWT is justly demonstrated by the fact that it was ridiculously easy to include the real proof of concept into this blog post; I only had to upload the GWT generated HTMLs and other files to a directory on my hosted server and include an iframe with a reference to the app. in this post!

For those interested in the details I include the links to the presentation as well as the source code of the prototype.

2 opmerkingen:

joshuadf zei

This is a good idea, but why not take it a step further? The GWT code could include an xPand "interpreter" and simply editing your xText changes your website without any cumbersome merging of old vs new Java classes.

Thomas Lyon zei

nice and good informative idea.i like this.php