Archive for category GWT

GWT 2.0 RC1 is out!

Logo GWTBruce Johnson:

Hi folks!
GWT 2.0 RC1 is now ready for you to try. The full documentation is still very much a work in progress, but you can at least start trying out the GWT SDK distribution and the Google Plugin for Eclipse using the following
instructions:
http://code.google.com/p/google-web-toolkit/wiki/GWT_2_0_RC
GWT 2.0 is going to be a big release, so don’t be surprised if there are a few bumps and surprises as we continue to finalize everything.

Read full announcement on GWT group


,

6 Comments

GWT is the present of web development

Logo GWTI’ve read a few articles by people who didn’t like GWT, but usually I don’t care to reply because it requires a lot of time to do it properly. However, today I came across this article on dzone: Lost in Translation or Why GWT Isn’t the Future of Web Development.

This one was troubling because it made good points on the way, some that I can’t agree more with (like the quality of Ext-GWT…) but it comes to a completely biased conclusion about GWT. So I took some time and wrote a reply

,

1 Comment

GWT: generating the factory

Controllers galore

In my current GWT project, we make heavy use of MVC, which means we have controllers and views all over the place. To link menu items and other actions to screens, the action item only keeps a reference to the controller class. This implies that we have to be able to instantiate the controller when the action is triggered.

No problem, we have a controllerClass, so we call controllerClass.newInstance(), right?

Well, not in the GWT world.

When you’re running the web version of your GWT application, due to the amount of meta-data that would have to be carried together with your code, Java reflection capabilities are not available. Which means that, even though the Class class exists, you can’t use it to list methods or fields, and you definitely can’t use it to obtain an instance of that class. This is a classic trap, because it might appear to work in hosted mode, simply because hosted mode runs in a standard JVM… but when you try to compile and run your application in web mode, you can forget it.

The poor man’s dynamic instantiation

Basically, the only option you have when you want to instantiate a class from a class reference, is to compare it with known classes, and when one is recognized, to call “new”, like this:

if (controllerClass == Controller1.class) {
  return new Controller1();
}
if (controllerClass == Controller2.class) {
  return new Controller2();
}
// (many lines omitted...)
throw new IllegalArgumentException("The class " +
 controllerClass.getName() + " is unknown in this factory.");

You can see how this is painful:

  • whenever you create a new controller, you have to remember to add it to this method, otherwise instantiation will fail during runtime
  • this method rapidly grows and becomes unmaintainable

To make things as clean as possible, this should be wrapped in a controller factory: a simple class that implements an interface with a single method

Controller createController(Class<? extends Controller> controllerClass) throws IllegalArgumentException;

While this hides the “details” of the implementation, it does not remove the burden of maintaining the factory method.

This is when GWT’s deferred binding mechanism can be useful. To compensate for the lack of runtime introspection, the GWT compiler can dynamically (during compilation) provide the best-suited implementation of an interface, or subclass of a given class. The client requests an implementation of this class by calling GWT.create(MyInterface.class).

The replacement class can be provided in one of two ways:

  • by substitution: under certain conditions, the class is substituted with an existing implementation. This is how GWT internally handles differences between browsers.
  • by generation: the implementation is constructed at compile-time by a Generator.

So why not use the second option and let the GWT compiler generate the factory class for us? It’s simple enough, we just need to generate an if statement for each known controller. So let’s try to do that.

Declaring the generator

First we need to tell the GWT compiler to invoke our generator, and when. Suppose our factory method is contained in an interface named ControllerFactory, then we just need to add the following lines to the GWT module file:

    <generate-with class="oge.gwt.rebind.ControllerFactoryGenerator">
         <when-type-assignable class="oge.gwt.client.ControllerFactory"/>
    </generate-with>

This translates to “when the client calls GWT.create() with a parameter class that is assignable to ControllerFactory, use ControllerFactoryGenerator to build the implementation class and return an instance of this class”. The interface must reside in the client package, but the generator must be somewhere else. The common practice is to put all generators in a package named “rebind”.

Next the generator itself.

Building the generator

The generator must implement the interface com.google.gwt.core.ext.Generator, which defines a single method:

generate(TreeLogger logger, GeneratorContext context, java.lang.String typeName)

where:

  • logger is used to log debug/info messages
  • context is used to obtain context information, and helpers to write the generated class
  • typeName is the name of the type being substitued; in our case this should always be “oge.gwt.client.ControllerFactory”

This method is invoked by the GWT compiler whenever the generate-with clause of the module is activated. The generated class must be written as full java source like you would write by hand; luckily some convenience methods exist.

The first thing the generator needs to decide is what the name of the generated class will be. The common practice is to add the “Impl” suffix to the interface name (we use “GeneratedImpl” to distinguish it from our hand-coded implementation).

This is how we do it:

public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {

 logger.log(TreeLogger.Type.INFO, "Generating " + typeName);

 this.typeName = typeName;
 TypeOracle typeOracle = context.getTypeOracle();

 try {
 // obtain JClassType instance for target type and construct target class name
 JClassType classType = typeOracle.getType(typeName);
 this.packageName = classType.getPackage().getName();
 this.className = classType.getSimpleSourceName() + "GeneratedImpl";

 // generate class source code
 generateClass(logger, context);

 } catch (Exception e) {
 logger.log(TreeLogger.ERROR, "Failed to generate implementation for " + typeName, e);
 }

 // return the fully qualifed name of the generated class
 return this.packageName + "." + this.className;
 }

Things to note:

  • we use TypeOracle (from the context) to obtain a JClassType instance for the type being substituted. TypeOracle and the associated classes (JClassType, JPackage, JField, JConstructor, JMethod, etc.) provide a powerful tool to query Java source and meta-information. It can be seen as the equivalent of native Java introspection. Once we have our JClassType instance, we can easily obtain the package name and class name.
  • if the generation succeeds, the method must return the fully qualified name of the generated class

Generating the class

The class generation itself requires the following steps:

  1. Begin source generation by calling context.tryCreate(logger, packageName, className). This method returns a PrintWriter, which we will use to write the source code. If it returns null, it means that the target class has already been generated and we can safely skip the generation.
  2. Instantiate a ClassSourceFileComposerFactory with the package name and class name. This is a utility class that helps building the target class.
  3. If necessary, call addImport(),  addImplementedInterface(), setSuperclass() on the ClassSourceFileComposerFactory instance.
  4. Obtain a SourceWriter by calling createSourceWriter(context, printWriter) on the instance of ClassSourceFileComposerFactory.
  5. Use methods of SourceWriter (println(), indent(), outdent(), …) to write the meat of the class.
  6. When you’re done, commit the generated source by calling context.commit(logger, printWriter).

This is how we do it for our controller factory:

private void generateClass(TreeLogger logger, GeneratorContext context) throws Exception {

 // get a PrintWriter to write source code to
 PrintWriter printWriter = context.tryCreate(logger, packageName, className);
 if (printWriter == null) {
 // source code has already been generated, abort
 return;
 }

 ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, className);
 composer.addImport("oge.gwt.client.mvc.Controller");
 composer.addImplementedInterface(typeName);

 SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter);

 generateCreateControllerMethod(sourceWriter, context.getTypeOracle());

 sourceWriter.println("}");

 // commit source generation
 context.commit(logger, printWriter);
 }

Almost done… now we only need to implement generateCreateControllerMethod(), which will generate the body of the method “createController()”. To do this, we need to generate a block like the following for each controller class that might be instantiated dynamically at runtime:

if (controllerClass == ControllerXXX.class) {
  return new ControllerXXX();
}

To do this, we wil simply iterate on all known classes by using getTypes() from TypeOracle, and retain only those that:

  • implement our substituted interface (ControllerFactory)
  • are public
  • are not abstract
  • have a public no-args constructor

These conditions are checked by using various methods on JClassType.

This is the result:

private void generateCreateControllerMethod(SourceWriter sourceWriter, TypeOracle typeOracle) throws Exception {

 // start method source generation
 sourceWriter.println("public Controller createController(Class<? extends Controller> controllerClass) throws IllegalArgumentException {");
 sourceWriter.indent();

 JClassType simpleViewClassType = typeOracle.getType("oge.gwt.client.mvc.Controller");

 JClassType classTypes[] = typeOracle.getTypes();
 for (JClassType classType : classTypes) {

 // we're only interested in subclasses of simpleViewClassType that are public and not abstract
 if (!classType.isAssignableTo(simpleViewClassType)
 || !classType.isPublic()
 || classType.isAbstract()) {
 continue;
 }

 // check that we have a no-arg constructor
 try {
 classType.getConstructor(new JType[] {});
 } catch (NotFoundException nfe) {
 continue;
 }

 System.out.println("Found controller: " + classType);
 sourceWriter.println("if (controllerClass == " + classType.getQualifiedSourceName() + ".class) {");
 sourceWriter.println("  return new " + classType.getQualifiedSourceName() + "();");
 sourceWriter.println("}");
 }

 sourceWriter.println("throw new IllegalArgumentException(\"The class \" + controllerClass.getName() + \" is unknown in this factory.\");");

 // end methods source generation
 sourceWriter.outdent();
 sourceWriter.println("}");

 }

Using the generated factory

Finally, we need to replace our old manual instantiation of the hand-coded ControllerFactoryImpl with a call to GWT.create() so that the generator mechanism is triggered:

//controllerFactory = new SimpleViewControllerFactoryImpl();
controllerFactory = GWT.create(SimpleViewControllerFactory.class);

Now when we GWT-compile the application, we will see our log message indicating that the generator is being called:

 Computing all possible rebind results for 'oge.gwt.client.ControllerFactory'
 Rebinding oge.gwt.client.ControllerFactory
 Invoking <generate-with class='oge.gwt.rebind.ControllerFactoryGenerator'/>
 Generating oge.gwt.client.ControllerFactory

The application should work exactly as before, since we only substituted a hand-written implementation of ControllerFactory with a computer generated version, which does exactly the same.

You will notice that the generator also gets called when you reload the hosted mode window… this makes sense, because you could very well have added a new Controller , in which case the factory needs to be updated. This is the only downside of this approach, but in my opinion the benefits are well worth the added overhead.

, , ,

10 Comments

GWT 2.0 milestone 2

Logo GWTJohn Labanca:

We are excited to release the second milestone build for GWT 2.0
today. This milestone is essentially feature complete, and provides
somewhat more stability in the various bits of core functionality that
will be coming in GWT 2.0.

The full announcement in GWT groups

The download

,

No Comments

Comparative study of AJAX frameworks – sort of…

I just came across yet another comparative study of AJAX “frameworks”.

When the author mentions that “GWT (…) can auto-generate AJAX-enabled JavaScript code from Java byte code”, it makes you wonder how much time he/she spent evaluating the options…

Finally, GWT stands out in the conclusion only because it is supported by Google.

No Comments

Announcing GWT 2.0 Milestone 1

Logo GWT
Amit Manjhi:

Hi everyone,
We are excited to release the first milestone build for GWT 2.0 today. This milestone provides early access (read: known to still be unfinished and buggy) to the various bits of core functionality that will be coming in GWT 2.0. Please download the bits from:

http://code.google.com/p/google-web-toolkit/downloads/list?can=1&q=2….

(…)

Announcing GWT 2.0 Milestone 1 – Google Web Toolkit | Google Groups.

,

2 Comments

Livre sur GWT: la sortie s’approche

Couverture(For the english speaking crowd: this is about the book I’m writing about GWT in french)

Le livre que je suis en train d’écrire portera sur GWT 1.7 et 2.0, et s’adressera plutôt aux développeurs Java qui souhaitent passer à GWT. La sortie est prévue en novembre aux éditions Dunod.

Le bout du tunnel approche ! Je mets actuellement la dernière main aux nouveautés de GWT 2.0, OOPHM, code splitting, UiBinder & co.

Pour info vous pouvez déjà précommander sur Amazon :)

, ,

2 Comments

Building GWT on the Mac

If you try to build the latest GWT from the svn repository on a Mac, you may end up with a bunch of errors like the following:

BUILD FAILED
/Users/ogerardin/Documents/GWT 2/trunk/build.xml:105: The following error occurred while executing this line:
/Users/ogerardin/Documents/GWT 2/trunk/build.xml:27: The following error occurred while executing this line:
/Users/ogerardin/Documents/GWT 2/trunk/build.xml:58: The following error occurred while executing this line:
/Users/ogerardin/Documents/GWT 2/trunk/platforms.ant.xml:36: The following error occurred while executing this line:
/Users/ogerardin/Documents/GWT 2/trunk/platforms.ant.xml:13: The following error occurred while executing this line:
/Users/ogerardin/Documents/GWT 2/trunk/dev/core/build.xml:192: The following error occurred while executing this line:
/Users/ogerardin/Documents/GWT 2/trunk/common.ant.xml:277: Non-zero status code result (1) running command: svn info

The last line indicates a problem with the “svn” command. The problem is that Mac’s builtin svn client is version 1.4.4 (wich you can check by typing “svn --version” in a terminal), but to build GWT, you need a newer svn client.

The steps to fix this are:

  • go to http://www.open.collab.net/downloads/community and download the latest subversion binaries for Mac OS X
  • you will get a disk image file; mount it and run the included installer. It will install to /opt/subversion/bin
  • edit your ~/.profile file to add the following line:
export PATH=/opt/subversion/bin:$PATH
  • start a new shell or type “. ~/.profile” to make sure the change is loaded in the current shell
  • type “svn --version” and check that the version is the latest one (1.6.5 as of today)
  • cd to your checked out GWT trunk directory, type “ant” and watch GWT build :)

, , , ,

No Comments

GWT + Snow Leopard: fixed with GWT 1.7.1

mac-logoGoogle has just released GWT 1.7.1 to fix the issue I mentioned a few days ago regarding Snow Leopard compatibility.

In short, you can now run GWT on Snow Leopard using the Java command line argument -d32 without further modification. The GWT SDK no longer directs you to only use Java 5.

http://googlewebtoolkit.blogspot.com/2009/09/gwt-171-release-fixes-mac-os-x-snow.html

,

No Comments

Porting Swing’s Action pattern to GXT (Ext-GWT)

ext_logoWhile working with GWT and GXT, it occurred to me that there was no equivalent in either to Swing’s Action architecture… So I set myself to implement an equivalent functionality in GXT.

The Swing legacy

In a word, the action architecture is an implementation of the Command design pattern, with the Action class being an abstraction of a command which is not bound to a specific UI component. Action implements ActionListener, which lets users perform it, namely by calling its actionPerformed method. An Action may also contain additional meta-information such as a name, a description, an icon, etc.

The cool thing with actions is that many Swing components (such as a JButton or a JMenuItem) are action-aware, which means that they can be constructed from an action instance. The data required to build the UI component, such as the button’s label, is taken from the Action’s meta-data. When the component is activated (read: clicked), the corresponding action’s actionPerformed method is then called.

Furthermore, if the action is disabled, then the corresponding UI component becomes disabled too. If you used the same Action instance to construct several UI components, they will all reflect the action’s disabled status! Now this is starting to get interesting…

Let’s see if we can make this happen with GXT.

Step 1: the Action classes

First we need an ActionListener interface:

import com.extjs.gxt.ui.client.event.BaseEvent;

public interface ActionListener {

    /**
     * Invoked when an action occurs.
     */
    void actionPerformed(BaseEvent e);

}

This is quite similar to Java’s original ActionListener interface, except that we use GXT’s BaseEvent instead of Java’s ActionEvent, for obvious reasons. The original ActionListener also inherited EventListener, which is not needed here.

Next we need an Action interface that allows UI components to fetch what they need to construct themselves (name, etc.). The original Action interface contains

  • a set of String constants that define the names of the properties (NAME, SHORT_DESCRIPTION, SMALL_ICON, etc.)
  • methods to get/set those properties
  • methods to add/remove a PropertyChangeListener so that we can be notified of changes

In native Java, the property-related methods are implemented completely in AbstractAction using ArrayTable and SwingPropertyChangeSupport, which means I would have to add a lot of code to duplicate the functionality.

Fortunately, GXT has a class called BaseModel which provides exactly the same set of functionality: named properties plus support for change listeners. So I slightly modified the Action interface so that GXT’s BaseModel would directly implement the property-related methods:

  • Object getValue(String key) becomes <X> X get(String key)
  • void putValue(String key, Object value) becomes <X> X set(String key, X value)
  • void addPropertyChangeListener(PropertyChangeListener listener) becomes void addChangeListener(ChangeListener... listener)
  • void removePropertyChangeListener(PropertyChangeListener listener) becomes void removeChangeListener(ChangeListener... listener)

Here is the full listing (most comments removed for brevity; see original Action Javadoc):

import com.extjs.gxt.ui.client.data.ChangeListener;

public interface Action extends ActionListener {
    /**
     * Useful constants that can be used as the storage-retrieval key
     * when setting or getting one of this object's properties (text
     * or icon).
     */
    public static final String DEFAULT = "Default";
    public static final String NAME = "Name";
    public static final String SHORT_DESCRIPTION = "ShortDescription";
    public static final String LONG_DESCRIPTION = "LongDescription";
    public static final String SMALL_ICON = "SmallIcon";
    public static final String ACTION_COMMAND_KEY = "ActionCommandKey";
    public static final String ACCELERATOR_KEY = "AcceleratorKey";
    public static final String MNEMONIC_KEY = "MnemonicKey";
    /**
     * The key used for storing the CSS icon style (added)
     */
    public static final String ICON_STYLE = "IconStyle";

    public <X> X get(String key);
    public <X> X set(String key, X value);

    public void setEnabled(boolean b);
    public boolean isEnabled();

    public void addChangeListener(ChangeListener... listener);
    public void removeChangeListener(ChangeListener... listener);
}

A few comments on this:

  • get/set methods are now generic (which must be good),
  • we use GXT’s ChangeListener instead of Java’s PropertyChangeListener, because that’s what GXT’s BaseModel supports
  • not all properties make sense in GXT, but I have kept them nonetheless. You never know…
  • I have added a property ICON_STYLE, which might be useful in a GWT context if we want to provide an icon as a CSS style rather than an Image.

Now we need an implementation of the Action interface that provides default behaviours for get/set methods and property change listeners; thanks to our little changes in Action, we just have to extend GXT’s BaseModel, which will handle most of the job.

import com.extjs.gxt.ui.client.data.BaseModel;

public abstract class AbstractAction extends BaseModel implements Action {

    /**
     * Specifies whether action is enabled; the default is true.
     */
    protected boolean enabled = true;

    public AbstractAction() {
    }

    public AbstractAction(String name) {
        set(Action.NAME, name);
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean newValue) {
        boolean oldValue = this.enabled;

        if (oldValue != newValue) {
            this.enabled = newValue;
            notifyPropertyChanged("enabled", newValue, oldValue);
        }
    }

}

That’s it! The get/set/addChangeListener/removeChangeListener methods are directly implemented by BaseModel and don’t even need to be redeclared here. I have dropped Cloneable and Serializable from the implemented interfaces because it doesn’t make much sense in a GWT context.

Step 2: the UI components

OK, now we have Actions that have properties, can notify changes, and can do something when they are performed. What we need to really make this useful is UI components that can accept an Action and will do what’s needed to translate that into UI stuff.

Let’s extend Menu so that we can call add(Action):

public class Menu extends com.extjs.gxt.ui.client.widget.menu.Menu {

    public boolean add(final Action action) {

        final MenuItem item = new MenuItem(action.get(Action.NAME));

        // Use the action's long description as tooltip
        String longDesc = action.get(Action.LONG_DESCRIPTION);
        if (longDesc != null) {
            item.setToolTip(longDesc);
        }
        item.setEnabled(action.isEnabled());

        item.addSelectionListener(new SelectionListener() {
            public void componentSelected(ComponentEvent event) {
                action.actionPerformed(event);
            }
        });

        // make sure changes in the "enabled" state of the action are propagated
        // to the MenuItem
        action.addChangeListener(new ChangeListener() {
            public void modelChanged(ChangeEvent event) {
                PropertyChangeEvent propertyChangeEvent = (PropertyChangeEvent) event;
                if (propertyChangeEvent.getName().equals("enabled")) {
                    boolean enabled = (Boolean) propertyChangeEvent.getNewValue();
                    item.setEnabled(enabled);
                }
            }
        });

        return add(item);
    }
}

The outline is very simple:

  • create a MenuItem
  • give it name, tooltip, state according to the Action
  • make sure that selecting it will trigger the action
  • make sure that if the “enabled” status of the action changes, the “enabled” status of the MenuItem changes accordingly
  • add the MenuItem

Now let’s do the same for a Button; in this case we’ll add a constructor that takes an Action :

public class Button extends com.extjs.gxt.ui.client.widget.button.Button {

    public Button() {
    }

    public Button(String text) {
        super(text);
    }

    public Button(String text, SelectionListener listener) {
        super(text, listener);
    }

    public Button(final Action action) {
        this(action.get(Action.NAME));

        // Use the action's long description as tooltip
        String longDesc = action.get(Action.LONG_DESCRIPTION);
        if (longDesc != null) {
            setToolTip(longDesc);
        }

        setEnabled(action.isEnabled());

        addSelectionListener(new SelectionListener() {
            public void componentSelected(ComponentEvent event) {
                action.actionPerformed(event);
            }
        });

        // make sure changes in the "enabled" state of the action are propagated
        // to the Button
        action.addChangeListener(new ChangeListener() {
            public void modelChanged(ChangeEvent event) {
                PropertyChangeEvent propertyChangeEvent = (PropertyChangeEvent) event;
                if (propertyChangeEvent.getName().equals("enabled")) {
                    boolean enabled = (Boolean) propertyChangeEvent.getNewValue();
                    setEnabled(enabled);
                }
            }
        });

    }
}

You get the picture, it’s easy to generalize this to any UI component.

Conclusion

With this pattern, you can now easily create a menu item and a button, linked to the same action. If the action becomes unavailable, you call Action.setEnabled(false), and automagically the button and menu item become disabled…

PS: some of the code here is directly taken from the JDK source; I believe this is legit use under the Java Research License, but if it is not, let me know.

, , ,

No Comments