Wednesday, January 20, 2010

Non-intrusive GWT 2 mod [2nd part]

As mentioned in the last post I want to describe how to register custom element parsers for GWT 2.0 ui binding. I use a Java Annotation @ElementParserToUse(className="your.Parser") (as suggested a few days ago by George Georgopoulos (ggeorg)). This Annotation is added to custom widgets which should be parsed in a custom way.

Element Parsers are registered on-demand (if not registered yet) by adding the highlighted lines to UiBinderWriter.getParserForClass(JClassType uiClass):

Additionally the following method has to be added to UiBinderWriter:

Note

The method getParserForClass(JClassType uiClass) is called within getParsersForClass(JClassType type) which iterates the class hierarchy of the current Widget (corresponding to the current .ui.xml element). Because of the class hierarchy is created by a breadth-first search algorithm it is ensured that parsers are returned from most specific to most general (in oo manner). That means that custom parsers do their job first. That's necessary because xml artifacts are consumed by the ui binder framework (at least they should be) and so there's no second chance to parse them.

In the next post [3rd part] I will introduce custom parsers for the Ext GWT Widgets shown in the post GWT 2 Declarative Layout: Beyond UIBinder.

Monday, January 18, 2010

Non-intrusive GWT 2 mod [1st part]

With the following modification 3rd party widget libraries are enabled to leverage GWT's new declarative ui binding feature. The goal is to add custom element parsers to the GWT framework. These parsers are responsible for generating java code from xml representations of layouts based on GWT widgets. The ability to add custom parsers is the key to ensure correct java code generation of (complex) custom widgets.

Currently the parsers are held in a private variable in UiBinderWriter. There's no way to access it, so UiBinderWriter has to be modified in some way. Rewriting UiBinderWriter and overwriting it in the corresponding jar (gwt-user.jar) is a brutal way which I don't recommend. The main reason is that all GWT applications based on that jar are affected. The following how-to describes a non-intrusive method which applies the modification at runtime (in memory).

Table of contents:

  1. Hook into UiBinder
  2. Create custom Generator
  3. Modify UiBinderWriter
  4. Note

Hook into UiBinder

GWT generates an implementation of UiBinder at runtime which is specific for the root widget of the .ui.xml and the java class which is aware of the widget instance. Here's the well known code which triggers the code generation:

The code generator UiBinderGenerator instantiates UiBinderWriter which is aware of the mentioned element parsers. So replacing UiBinderGenerator is a way to also replace UiBinderWriter. Because GWT offers the ability to hook in custom generators within the GWT module configuration, com.google.gwt.uibinder.rebind.UiBinderGenerator can be overwritten with a custom one (here: cafebab3.rebind.custom.UiBinderGenerator). The GWT.create(...) method is taking care of this. Corresponding snippet of the main .gwt.xml:

As a result GWT binds every .ui.xml via cafebab3.rebind.custom.UiBinderGenerator.

Create custom Generator

I didn't want to re-implement the whole UiBinderGenerator. Instead I use delegation where the delegate is the original UiBinderGenerator. The 'trick' is to load the delegate with a custom ClassLoader which returns a modified UiBinderWriter class if it is asked for the original one. We know it is asked eventually because the original UiBinderGenerator instantiates one.

Here's the (one hell of a) ClassLoader. It needs the modified UiBinderWriter.class to be renamed to UiBinderWriter.bytecode and placed in the same package.
UPDATE: Fixed an issue with requesting specific classes several times.

The *magic* Bytecode class used in the UiBinderClassLoader is needed to locate all classes, fields and methods with default visibility (= package private visibility) (or which are protected) and make them public (= unlock them). This is necessary because two classes A and B with default visiblity, which are in the same package, don't see each other if they are loaded by different ClassLoaders (internally the ClassLoader is part of the namespace in addition to the package). I thought about using an existing bytecode manipulation library like ASM but these libraries are huge (asm.jar > 40 mb) and so I decided to implement my own one. The result is a tiny class which only modifies access flags. This 'unlocking' of bytecode takes round about 10 ms when called first time, and 0 to 1 ms when called subsequently (tested on my notebook).

Caution: Bytecode manipulation should be considered as a hack. Changing the visibility of classes, methods or fields may also be a change of the semantic of the java program (if it uses reflection for example).

Modify UiBinderWriter

All the steps above are nice but not necessary if the modified UiBinderWriter is copied directly into the corresponding jar (gwt-user.jar) which I decided to be no good idea because it is intrusive.

Recalling that the goal is to supply custom element parsers. At compile time the custom 3rd party widget parsers are not known by the GWT framework. My preferred solution is to annotate widgets with a hint which parser to use. When initializing the pool of parsers, all packages have to be searched for Widgets. Finding such an annotation containing a parser hint this hint will be taken into account.

The implementation of the UiBinderWriter modification will be shown in my next post. Additionally I will give an example for ui binding GXT widgets. Stay tuned!

Note

Manually copying the modified UiBinderWriter.class is crude. A simple way to provide the file UiBinderWriter.bytecode is to create an additional project (next to the GWT project), including the GWT libraries and the modified UiBinderWriter (in the package com.google.gwt.uibinder.rebind). Deployment to the GWT project can be done like this:

Don't forget to refresh the workspace when manually copying files into it!

Thursday, December 31, 2009

Denmark 09/10

Greetings from Denmark and best wishes for 2010!

Sunday, December 20, 2009

[UPDATE] GWT 2 Declarative Layout

Studying the Google-Web-Toolkit code led me to the method UiBinderWriter.registerParsers():

Ray Ryan (rjrjr) seems to already have the infrastructur for plugging additional parsers into the ui binder. I'll go deeper into this...

Saturday, December 19, 2009

GWT 2 Declarative Layout: Beyond UiBinder

Google Web Toolkit (GWT) 2 brings Declarative Layout

Google brought with GWT 2.0.0 a new major release of Google Web Toolkit (GWT) to us some days ago. This toolkit enables java guys (including girls!) to write rich internet applications based on javascript and ajax.
The version 2 of the toolkit is bundled with great new tools and features (also have a look here). One of these features is declarative layout with UiBinder. UiBinder "now allows you to create user interfaces declaratively in XML instead of having to assemble them programmatically". Here's an example...

Programmatical approach (common style):

*) With the use of setters instead of constructor arguments I intend to understate the nature of layouting gwt applications programmatically.

Corresponding declarative code (new style):

In real-world projects your program will be a mixture of the two approaches. The xml based ui declarations will unclutter your code and separate the layout from the logic. Because xml is static (like a plain html page) the declared Widgets (or UIObjects in general) can be injected into java fields and dynamically modified at runtime. Because GWT translates your code into javascript, the modifications will occur at the client side. Sounds easy - and that's what it is. Thank you, Google!

Do 3rd Party GWT Libraries work with GWT 2?

Yes and no. Considering the programmatical point of view all should work fine. The only point of interest is the case where third party Widgets are build on top of standard GWT Widgets which were changed with the new version in some way (UPDATE: this is theory - I don't know if there are api changes). This should be a minor problem because if the third party library is a good choice then it will be updated soon. If not it should be replaced by a good choice ;-)

The more interesting point of view is the one where declarative layouts are considered. GWT 2 ui declarations are allowing the import and usage of 3rd party Widgets. For example let's substitute the center component of the above standard GWT example with a DatePicker of the Ext GWT (GXT) 2.1 library. You see the complete ui.xml because the use of namespaces is essential here:

I will not describe the technical details of how to integrate a third party GWT library and get it running. The focus here is set on the ability to declare layouts with (a mixture of) Widgets from different GWT libraries. Let's take a look at the following GXT snippet:

The question is now how to formulate this in a declarative manner... The answer is simple but dissatisfying: It is currently not possible.

As we see with DatePicker in the example above, GWT is able to construct simple Widgets (by calling their constructor with no arguments). If GWT finds attributes in a declaration it will call the corresponding setters of the associated java object (follwing the Java Beans standard). But there are more complex Widgets where this strategy does not work. The ContentPanel of GXT can be configured with a specific layout strategy. The default is FlowLayout but in the example BorderLayout is used. Depending on the layout the LayoutData has to be set appropriately when adding children to the ContentPanel. This leads to the assertion that the declarative layout parser has to know the structure of the xml presentation of each (3rd party) Widget and how to wire together the underlying Widgets to an object graph.

How would you formulate the above example as ui declaration? Here's one of several possible answers: UPDATE: Here's an answer, depending on a specific parser:

How to get it work?

Currently I work on a solution for the described problem of declaring layouts containing arbitrary Widgets of 3rd party libraries. I am focusing on these key topics:

  1. Hooking into the code generator of GWT (finished)
  2. Creating a custom code generator (work in progress)
  3. Defining a plugin language for 3rd party customization of the code generator (next step)

UPDATE: I realized, that it is possible to write specific element parsers which are bound to an UiBinder element via reflection. There are two things to do now:

  1. Write specific parsers for 3rd party Widgets (few code because recursive)
  2. Register these parsers (access private var UiBinderWriter.elementParsers)

The discussion of these three topics will follow soon on this blog... A parser for the last example will be posted on this blog soon...

Thursday, December 10, 2009

XML Schema: Element References

Consider a xml based language consisting of elements (here: nodes) and references to elements (here: nodeRefs). In the following I want to discuss if it is possible to create a xml schema for such a language which

  • allows to express reference dependencies
  • has a base type for an arbitrary number of nodes; a node reference is a node too!
  • is aware of referential integrity

Here is an example of a xml document based on a language which consists of two different nodes and a node reference:

A node either has an unique id (and therefor is enabled to be referenced) or a reference to an id. This property can be denoted with an attributeGroup:

The type of id is not xs:ID because it is possible to omit the id. In this case the node is not enabled to be referenced. The second reason is that references are nodes too. The type xs:ID would force that all nodes have an id - even node references.

In general there are multiple types of nodes which can be referenced. The reference itself is a node too. So we need a base type for node definitions and node references which is an abstract node. In this example a node can have child nodes.

The node definition has optionally an unique id which enables it to be referenced. The ref attribute is prohibited. Because the node type is a restriction the child element has to be denoted again! The node definition is abstract because there are several concrete types of node definitions.

In this example there are two different types of concrete node definitions:

A node reference has no child elements! The id attribute is ommitted because node references cannot be referenced. This can be modeled by using direct references to concrete nodes (no need for transitivity).

The root element encapsulates an arbitrary number of nodes and defines the referential integritiy constraints.

There is one flaw: Xml schema does not allow to create a keyref where the corresponding key is a unique constraint. I don't understand that! It would make sense to allow the specification of attributes which have to be unique within a document for those elements for which they are defined. @W3C: What the reason for that restriction!?

Here is the complete example.xsd:

Of cause there are several other possibilities to model a xml schema for such a language. Here is another (which doesn't match the starting example.xml exactly but shows a different approach with choices):

If you use jaxb to unmarshall a xml file (based on a xsd) I discourage the use of choice elements. They are mapped to multiple java instance variables which are null if not used. Instead I recommend the usage of abstract elements which are mapped to abstract classes. This is a more OO like way.

Tuesday, November 24, 2009

Local Subversion repository with Eclipse

Today I installed Subversion (SVN) on my notebook. I needed versioning for local development. A simple way is to create a file-based repository and connect to it with an eclipse svn client. Follow these steps:

  • Download & install Subversion for Mac
  • Install Eclipse Subversion client plugins
  • Share an Eclipse project in a local repository

Here are the details:

Download & install Subversion for Mac

You can get Subversion for Mac (and other OS's) here. I used the universal openCollabNet binary. Just follow the install instructions of the installer...

It is recommended to add the Subversion bin directory to the system $PATH variable (if you're lazy like me). For example you can edit one of the following files:

  • /etc/profile (system wide .profile for sh)
  • /Users/<you>/.profile (users .profile, loaded at login)
  • /Users/<you>/.bash_profile (users .profile, (re-)loaded with new terminal window)

The .bash_profile was my choice but you can use all of them. Add the following lines:

Btw: Currently I use the non-commercial editor TextWrangler. It's a great tool! The shell command edit <file> opens a gui editor for <file>.

Install Eclipse Subversion client plugins

There are currently two popular SVN plugins for Eclipse: Subclipse and Subversive. The latter is my favourite:

  1. Click Help and Install New Software
  2. Install Subversive SVN Team Provider
    • Choose Site: Galileo (included in Eclipse 3.5)
    • Install: Subversive SVN Team Provider (Incubation)
  3. Install Subversive SVN Connectors
    • Choose site: http://www.polarion.org/projects/subversive/download/eclipse/2.0/update-site/
    • Install: Subversive SVN Connectors SVNKit 1.3.0 Implementation
  4. Restart Eclipse, if asked

Share an Eclipse project in a local repository

Open a terminal (current location: /Users/<you>) and create a local SVN repository:

In the Eclipse Project Explorer richt-click on a project and...

  • Choose Team -> Share Project...
  • Repository Type: SVN
  • Create a new repository location
  • Enter URL: file:///Users/<you>/svn.repository/myFirstRepository and press Finish
  • Finally add the project to repository

Use the Team Synchronization perspective to sync your changes.