Posts mit dem Label GWT werden angezeigt. Alle Posts anzeigen
Posts mit dem Label GWT werden angezeigt. Alle Posts anzeigen

20.07.2011

GWT: UiBuilder Internationalisation the simple way

UiBinder, the tool for declarative UIs for GWT, can of course be internationalised. The procedure is explained in the GWT docs. But this approach looks a little bit too complex to me, especially because I already have a simple I18N interface for my App. I would like to use that one and have only one place to add translations to.

GWT I18N, recalled


GWT provides us with a very simple way of doing I18N. Simply create an interface like that one:
public interface Text extends Messages {
 public static final Text LANG = GWT.create(Text.class);
 String create();
 String save();
 String delete();
}
In the same folder, put a properties file called Text.properties:
create=Create
save=Save
delete=Delete
and for your german user, for example, add another text file Text_de_DE.properties:
create=Neu
save=Speichern
delete=Löschen
In order to set the correct locale from the users request, I usually convert from index.html to index.jsp (do not forget to change your welcome file in web.xml, too) and add:
<meta name="gwt:property" 
         content="locale=<%= request.getLocale() %>">
Finally, add this to your Module.gwt.xml:
<inherits name="com.google.gwt.i18n.I18N"/>
  <extend-property name="locale" values="en"/>
  <extend-property name="locale" values="de_DE"/>
  <set-property-fallback name="locale" value="en"/>
Now, instead of writing string literals in your app code, use this interface:
Button save = new Button(Text.LANG.save());


Now, what about UiBuilder?


The recipe for I18N of UiBuilder templates describe a procedure where the property files above can be generated from annotated templates. Cool, but you know, I do not want two different techniques and qould like to re-use the simple Text interface from above.

And of course this is simple. As explained here, import the interface as an external resource and simply use it:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
   xmlns:g="urn:import:com.google.gwt.user.client.ui"
   xmlns:t="urn:import:de.joergviola.tripmark.client.util">
 <ui:with field='i18n' type='de.joergviola.tripmark.client.i18n.Text'/>
 <g:HorizontalPanel spacing="3">
   <g:Anchor text="{i18n.save}" ui:field="save"/>
   <g:Anchor text="{i18n.delete}" ui:field="delete"/>
 </g:HorizontalPanel>
</ui:UiBinder>
That's it - simple, eh?

06.07.2011

GWT MVP made simple

GWT Model-View-Presenter is a design pattern for large scale application development. Being derived from MVC, it divides between view and logic and helps to create well-structured, easily testable code. To help lazy developers like me, I investigate how to reduce the amount of classes and interfaces to write when using declarative UIs.

Classic MVP


You know how to post a link in facebook? - Recently I had to create a this functionality for a little GWT travelling app.
So you can enter a URL, which is then fetched and parsed. You can select one of the images from the page, review the text and finally store the link.
Now how to properly set this up in MVP? - First, you create an abstract interface resembling the view:
interface Display {
  HasValue<String> getUrl();
  void showResult();
  HasValue<String> getName();
  HasClickHandlers getPrevImage();
  HasClickHandlers getNextImage();
  void setImageUrl(String url);
  HasHTML getText();
  HasClickHandlers getSave();
}
It makes use of interfaces GWT components implement that give some access to their state and functionality. During tests you can easily implement this interface without referring to GWT internals. Also, view implementation may be changed without influence on deeper logic.
The implementation is straightforward, shown here with declarated UI fields:
class LinkView implements Display
  @UiField TextBox url;
  @UiField Label name;
  @UiField VerticalPanel result;
  @UiField Anchor prevImage;
  @UiField Anchor nextImage;
  @UiField Image image;
  @UiField HTML text;
  @UiField Button save;
  public HasValue<String> getUrl() {
    return url;
  }
  public void showResult() {
    result.setVisible(true);
  }
  // ... and so on ...
}
The presenter then accesses the view using the interface, which by convention is written inside the presenter class:
class LinkPresenter
  interface Display {...};

  public LinkPresenter(final Display display) {
    display.getUrl().addValueChangeHandler(new ValueChangeHandler<String>() {
      @Override
      public void onValueChange(ValueChangeEvent<String> event) {
        Page page = parseLink(display.getUrl().getValue());
        display.getName().setValue(page.getTitle());
        // ...
        display.showResult();
      }
    });
   }
   // ... and so on ...
}

So here we are: Using MVP, you can structure your code very well and make it easily readable.

The simplification


The payoff is: Three types for each screen or component. Three files to change whenever the UI is re-defined. Not counted the ui.xml file for the view declaration. For a lazy man like me, these are too many. And if you take a look at the view implementation, it is obvious how to simplify this:
Use the view declaration (*.ui.xml) as the view and inject ui elements directly into the presenter:
class LinkPresenter
  @UiField HasValue<String> url;
  @UiField HasValue<String> name;
  @UiField VerticalPanel result;
  @UiField HasClickHandlers prevImage;
  @UiField HasClickHandlers nextImage;
  @UiField HasUrl image;
  @UiField HasHTML text;
  @UiField HasClickHandlers save;

  public LinkPresenter(final Display display) {
    url.addValueChangeHandler(new ValueChangeHandler<String>() {
      @Override
      public void onValueChange(ValueChangeEvent<String> event) {
        Page page = parseLink(url.getValue());
        name.setValue(page.getTitle());
        // ...
        result.setVisible(true);
      }
    });
   }
   // ... and so on ...
}
Since it is possible to declare the injected elements using their interfaces this presenter has a lot of the advantages of the full-fledged MVP presenter: You can test it by setting implementing components (see below) and you can change the views implementation easily.
But now, you have it all in one class and one view.ui.xml-file and you can apply structural changes much simpler.

Making UI elements abstract

TextBox implements HasValue<String>. This is simple. But what about properties of ui elements that are not accessible through interfaces? An example you may already have recognized is the VerticalPanel named result in the above code and its method setVisible(), which unfortunately is implemented in the UiObject base class. So no interface is available that could eg. be implemented at test time. For the sake of being able to switch view implementations, it would be better to inject a ComplexPanel, but even that cannot be instantiated at test time.

The only way out in this case is to create a new Interface, say
interface Visible {
  void setVisible(boolean visible);
  boolean isVisible();
}
and subclass interesting UI components, implementing the relevant interfaces:
package de.joergviola.gwt.tools;
class VisibleVerticalPanel 
       extends VerticalPanel 
       implements Visible {}
This seems to be tedious and sub-optimal. Nonetheless, is has to be done only per component and not per view as in the full-fledged MVP described above.
Wait - how to use self-made components in UiBuilder templates? - That is simple:
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:t="urn:import:de.joergviola.gwt.tools">
   <g:VerticalPanel width="100%">
    <g:TextBox styleName="big" ui:field="url" width="90%"/>
    <t:VisibleVerticalPanel ui:field="result" 
                      visible="false"  width="100%">
    </t:VisibleVerticalPanel>
   </g:VerticalPanel>
</ui:UiBinder>

Declaring handlers


The standard way of declaring (click-)handlers is very convinient:
@UiHandler("login")
 public void login(ClickEvent event) {
  srv.login(username.getValue(), password.getValue());
 }
In the simplified MVP approach, this code would reside in the presenter. But the ClickEvent parameter is a View component and can eg. not be instantiated at runtime. On the other hand, it cannot be eliminated from the signature because UiBuilder requires an Event parameter.

So unfortunately one has to stick back to registering ClickHandlers manually (as one has to do in full MVP anyway):
public initWidget() {
       ...
       login.addClickHandler(new ClickHandler() {
               @Override
               public void onClick(ClickEvent event) {
                       login();
               }
       });
       ...
}

public void login(ClickEvent event) {
        srv.login(username.getValue(), password.getValue());
}

Testing

Making your app testable is one of the main goals when introducing MVP.
GwtTestCase is able to execute tests in the container environment but requires some startup-time. In TDD, it is desirable to have very fast-running tests that can be applied after every single change without loosing context.
So MVP is designed to be able to test all your code in a standard JVM. In standard MVP, you create implementations of the view interfaces. In this simplified approach, it is sufficient to create implementations on a component interface level like the following:
class Value<T> implements HasValue<T> {

  private T value;
  List<ValueChangeHandler<T>> handlers = 
                     new ArrayList<ValueChangeHandler<T>>();

  @Override
  public HandlerRegistration addValueChangeHandler(
    ValueChangeHandler<T> handler) {
   handlers.add(handler);
   return null;
  }

  @Override
  public void fireEvent(GwtEvent<?> event) {
   for (ValueChangeHandler<T> handler : handlers) {
    handler.onValueChange((ValueChangeEvent) event);
   }
  }

  @Override
  public T getValue() {
   return value;
  }

  @Override
  public void setValue(T value) {
   this.value = value;
  }

  @Override
  public void setValue(T value, boolean fireEvents) {
   if (fireEvents)
    ValueChangeEvent.fire(this, value);
   setValue(value);
  }

 }
As usual, you have to inject this component into the presenter-under-test. Though in principle, you could create a setter for the component, I stick to the usual trick to make the component package-protected, put the test into the same package (but of course different project folder) as the presenter and set the component directly.

What do you win?

You get code structered as clean as in full MVP with much less classes and boilerplate code.
Some situations require utility classes for components and their interfaces, but as time goes by, you build an environment which is really easy to understand, test and extend.

I'm curios: Tell me your experiences!

18.11.2010

GWT: Controlling async processes

In this article, I present a simple class which makes it easy to start async processes, show its state to the user and handle the results.

Perhaps one of the most appealing features of GWT is the handling of async remote calls. It is really easy. Recently I realized the following pattern often used in my apps: Upon a click, an async call is triggered and after that one finished, the user interface is updated. So I have to add a ClickHandler, start the RPC call and specify an AsyncCallback. Simple enough.

On the other hand, I have lots of these interactions. And I want to display a nice little spinning wheel beside the Anchor starting the request as long as it runs. Ah... and I want a server error, if happened, to be displayed beneath that wheel.

Here the game becomes less nice and code less clean. This is why I started organizing it around the following little component:

public abstract class ProgressFlag<T> extends Image implements
HasClickHandlers, ClickHandler, AsyncCallback<T> {

public ProgressFlag() {
super("/progress.gif");
setVisible(false);
}

@Override
public void onFailure(Throwable caught) {
finish();
Window.alert(caught.getMessage());
}

@Override
public void onSuccess(T result) {
onReady(result);
finish();
}

private void finish() {
setVisible(false);
}

public abstract void onReady(T result);

public abstract void onStart();

@Override
public void onClick(ClickEvent event) {
setVisible(true);
onStart();
}
}

As you can see, this little component acts as a ClickHandler as well as an AsyncCallback and redirects to new abstract methods. Now, you can simply implement and use it:

private ProgressFlag<Person> savePerson =
new ProgressFlag<Person>() {






public void onStart() {
          srv.savePerson(person, this);
        }
public void onReady(Person result) {
          Window.alert("Person saved: "+person.getName());
        }
}
...
button.addClickHandler(savePerson);
add(button);
add(savePerson);
So now I only have to state how the call is started and what should happen when it succeeds. Errors are always handled the way I want to and I have my spinning wheel which is an important feature of a UI with asynchroneous RPC.




10.11.2010

GWT Internationalisation Checklist

Follow these steps to internationalize you GWT app and show the language corresponding to the locale the browser sent:


Turn your welcome page to a dynamic jsp by changing your web.xml

  <welcome-file-list>
    <welcome-file>
      your-welcome-file.jsp
    </welcome-file>
  </welcome-file-list>

So rename your welcome page, presumably .html, to .jsp. In the welcome page header, add:

    <meta name="gwt:property" 
      content="locale=<%= request.getLocale() %>">

Now add I18N to your app by adding the following line to your *.gwt.xml:

  <inherits name='com.google.gwt.i18n.I18N'/>

For each locale you want to provide, add another line like these:

  <extend-property name="locale" values="en_US"/>
  <extend-property name="locale" values="de_DE"/>

Now the GWT-App delivered to the client is configured to use the locale sent by her browser.
Next, create an interface extending Messages, e.g.:

public interface Text extends Messages {
public static final Text LANG = 
          GWT.create(Text.class);

String welcome(String name);
}

Now you can externalize your static String. For example, substitute
new Label("Hello "+name);

with
new Label(Text.LANG.welcome(name));

The GWT-magic, on GWT.create provides you with an implementation of your interface that is bound to i18n-property files. So create a File Text.properties in the package of the interface:

  welcome = Hello {0}

You are free to add more resources by providing more methods in your interface and the corresponding line in the properties file. If you want a, say, german translation, create Text_de_DE.properties:

  welcome = Guten Tag {0}

Voilà!

Of course, there are a lot more options in GWT I18N, like setting locales explicitely or use constant string and the like. Therefore do not miss the original documentation.

03.11.2010

GWT Serialisation of baseclass

Ups - did you know?
Base classes of Serialisable classes have to be serialisable, too!
Consider:

public abstract class Base {
  private long id;
  public long getId() { return id; }
  public void setName(long id) { this.id=id; }
}
public class Person extends Base 
  implements Serializable {
  private String name;
  public String getName() { return name; }
  public void setName(String name) 
    { this.name=name; }
}
Now transferring Person as a parameter to or result of a standard GWT RPC call would result in id==0 at the receiving side no matter what value it had on the sending side.

This was rather surprising to me but simple to repair:
public abstract class Base 
  implements Serializable {
  ...
}