Showing posts with label GWT. Show all posts
Showing posts with label GWT. Show all posts

Wednesday, March 03, 2010

Building a GWT Declarative Interface

Introduction

GWT 2 has introduced the concept of declarative interfaces, that is, the interface can be described via an XML document, rather than built using code. The idea isn't new, it's seen in many new technologies such as Macromedia Flex, ASP.Net and JavaFX, however to the GWT developer it means the end of writing reams of boiler plate code.

In this post I show you how to create a simple Image Gallery widget that has a declarative interface and then how to create bigger interfaces using these widgets.

The Basic Widget

Before we do anything, we need to define the basic ImageGalleryWidget, in our case, it looks as so :

public class ImageGalleryWidget extends Composite {
 private GalleryImage[] images;
 private int currentImageIndex = 0;
 
 public ImageGalleryWidget() {
 }
 
 public void setTitle(String value) {
 }
 
 public void setImages(GalleryImage[] images) {
  this.images = images;
  currentImageIndex = 0;
 }
 
 public static class GalleryImage {
  private final String caption;
  private final String url;
  
  public GalleryImage(String url, String caption) {
   this.caption = caption;
   this.url = url;
  }
  
  public String getUrl() {
   return url;
  }
  
  public String getCaption() {
   return caption;
  }
 }
}

As you can see, our ImageGallery has two properties: a title, and an array of images to display. Each image has the URL of the actual file, and a caption. You'll also notice that our widget doesn't extend Widget but rather Composite, this is important as we'll see later.

Defining the Interface

GWT allows you to use the declerative method to define interfaces of individual components, in this case the interface for a particular widget. Before we go any further, it would be a good idea to show the UI for our image gallery:

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
      xmlns:g='urn:import:com.google.gwt.user.client.ui'>

  <g:VerticalPanel spacing="3">
   <g:Cell horizontalAlign="CENTER" cellSpacing="40" width="100%">
    <g:Label ui:field="title"/>
   </g:Cell>
   <g:Cell>
    <g:Image ui:field="image"/>
 </g:Cell>
 <g:Cell width="500px">
    <g:HorizontalPanel spacing="5" width="100%">
     <g:Cell>
      <g:Button text="Prev" ui:field="btnPrev"/>
     </g:Cell>
     <g:Cell>
      <g:Label ui:field="caption"/>
     </g:Cell>     
     <g:Cell>
      <g:Button text="Next" ui:field="btnNext"/>
     </g:Cell>
    </g:HorizontalPanel>
 </g:Cell>  
  </g:VerticalPanel>
</ui:UiBinder>

First lets look at the namespace declarations. The first binds the prefix ui to urn:ui:com.google.gwt.uibinder which identifies GWT specific elements to the parser such as the UiBinder element; it will be required on every declared interface file. The next namespace urn:import:com.google.gwt.user.client.ui imports elements from the com.google.gwt.user.client.ui package, (the standard GWT Widget package) to be used in the interface. You can see some of these objects in use such as g:VerticalPanel. We'll come back to imported elements later.

Inside the UiBinder element you define your interface by specifying widgets to be instantiated. In this case we're creating a standard VerticalPanel widget with Cells for each row. In the top cell we're adding a label, the next we're adding an Image, and the bottom cell holds a HorizontalPanel which contains the Prev and Next buttons. As you'll appreciate, this interface file is a lot easier to read and modify than if it had been defined in standard Java.

Certain elements in our file have a special ui:field attribute defined. This is a special declarative attribute which tells GWT which field within the associated Java class (we'll get to that shortly), should hold a reference to that component.

Our widget is called ImageGalleryWidget and therefore the declarative XML file should be saved in the same package with the name ie. ImageGalleryWidget.ui.xml

Binding To A Java Class

The XML defines the UI, however a UI doesn't exist by itself, we need a way of referencing elements so that we can set and retrieve properties. In order to do this we need to add elements to the ImageGalleryWidget :

public class ImageGalleryWidget extends Composite {
 interface ImageGalleryUiBinder extends UiBinder<VerticalPanel, ImageGalleryWidget> {}
 private static ImageGalleryUiBinder uiBinder = GWT.create(ImageGalleryUiBinder.class);
 
 @UiField Image image;
 @UiField Label caption, title;
 @UiField Button btnNext, btnPrev; 

 // .... Rest Ignored ... 
} 

The first line defines an interface which will act as the binder, that is, it will set the field elements annotated by UiField. An implementation of this interface will be created by the GWT compiler. The second line is a standard GWT deferred binding create statement need to instantiate the generated binder class.

The next thing we need to do is perform the binding magic to apply values to our UiFields. This is done using the binder as so :

 public ImageGalleryWidget() {
  initWidget(uiBinder.createAndBindUi(this));
 }

Here, the binder instance, created using deferred binding, is told to bind the interface file elements to the UiField elements in this class. The return from this call is a VerticalPanel, which if you remember, is the root panel from our UI XML. If this was a standard Widget, we'd only be able to set an Element, however, because this is a Composite Widget, we're able to set a child widget using initWidget method.

NOTE: The name of the field in the class being bound to MUST be exactly the same as the ui:field entry, including case.

Now we have UI element bindings, we can treat this as if the UI had been created using the standard Java approach. Here, for example, are the setTitle and setImages methods :

 public void setTitle(String value) {
  title.setText(value);
 }
 
 public void setImages(GalleryImage[] images) {
  this.images = images;
  currentImageIndex = 0;
  displayImage();
 }
  
 private void displayImage() {
  image.setUrl(images[currentImageIndex].getUrl());
  image.setTitle(images[currentImageIndex].getCaption());
  caption.setText(images[currentImageIndex].getCaption());
 }

Adding Event Handlers

As it stands, our image gallery would simply display the first image in the array, what we need to do now is listen for Click events on the Prev and Next buttons in order to display other images.

In standard GWT we'd have to add anonymous ClickHandlers, but with the declarative interface we can use features of the generated UiBinder to do the work for us. For example, here's the click handlers for the buttons:

 @UiHandler("btnPrev")
 public void handlePrev(ClickEvent event) {
  if (currentImageIndex != 0) {
   currentImageIndex--;
   displayImage();
  }
 }

 @UiHandler("btnNext")
 public void handleNext(ClickEvent event) {
  if (currentImageIndex != images.length -1) {
   currentImageIndex++;
   displayImage();
  } 
 } 

In both cases, the UiHandler annotation tells GWT which UiField field this handler is for. The name of the method itself doesn't matter, it can be anything you like. In order to set the handler, GWT will look at the event and discover the name of the Handler class. It will then look for a method call add on the widget the event is being bound to. For example, if we had an event called MySimpleEvent that had an associated handler called MySimpleHandler, GWT would look for a method called addMySimpleHandler on the Widget specified in the UiHandler annotation.

A Quick Test

Before we go any further, it would be good to test this Widget. Here's an example of using the Widget, using photos from Flickr

public class UIBinderExample implements EntryPoint {

 private static final GalleryImage[] images = {
 new GalleryImage("http://farm4.static.flickr.com/3309/3622157565_fd079ac983.jpg","Bishop's Moat"),
 new GalleryImage("http://farm2.static.flickr.com/1257/928632149_71d88ac137.jpg","Family Of Goats"),
 new GalleryImage("http://farm1.static.flickr.com/61/193636096_1f34d7a78d.jpg","Wooden Boat - Sailing - Port Townsend")};
 
 public void onModuleLoad() {
  ImageGalleryWidget widget = new ImageGalleryWidget();
  widget.setImages(images);
  widget.setTitle("Sample Flickr Gallery");
    
  RootPanel.get().add(widget);
 }
}

Adding Style

At the moment the widget doesn't look very good; let's improve that by adding some CSS styles. To do this we first add a ui:Style element to our UI definition.

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
    xmlns:g='urn:import:com.google.gwt.user.client.ui'>

  <ui:style>
   .caption {font-weight:bold;width:100%}
   .button {color:red}
   .image {width:375px; height:500px}
  </ui:style>
  
  <!-- Rest Ignored -->
</ui:UiBinder>

We can then use those styles by setting the styleName property of the relevant elements, ie :

   <g:Cell>
    <g:Image styleName="{style.image}" ui:field="image"/>
 </g:Cell>

Reusing this Widget

GWT allows you to build up your UI using different definition files. What we'll do now is reuse this initial Widget in a new UI that is itself declared using XML. In order to do this we'll define a UI that uses two versions of this Image Gallery, and looks like so

<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' 
    xmlns:g='urn:import:com.google.gwt.user.client.ui'
    xmlns:d='urn:import:com.maddison.client.widgets'>
    
 <g:HorizontalPanel spacing="5" width="100%">
  <g:Cell>
   <d:ImageGalleryWidget title="Gallery One" ui:field="galleryOne"/>
  </g:Cell>
  <g:Cell>
   <d:ImageGalleryWidget title="Gallery Two" ui:field="galleryTwo"/>
  </g:Cell>
 </g:HorizontalPanel>    
</ui:UiBinder>

The important part of this file is the urn:import:com.maddison.client.widgets namespace declaration. This states that widgets marked with the d namespace can be found in the com.maddison.client.widgets package. Properties on this Widget (for example the title) are set by calling a setXXX method on the given widget.

To show another feature of the declarive API, lets save this file as MainAppInterface.ui.xml. Our application will be defined in a Composite widget that looks like so :

public class MyApp extends Composite {
 @UiTemplate("MainAppInterface.ui.xml")
 interface MyAppUiBinder extends UiBinder<HorizontalPanel, MyApp> {}
 private static MyAppUiBinder uiBinder = GWT.create(MyAppUiBinder.class);

 private static final GalleryImage[] images = {
  new GalleryImage("http://farm4.static.flickr.com/3309/3622157565_fd079ac983.jpg","Bishop's Moat"),
  new GalleryImage("http://farm2.static.flickr.com/1257/928632149_71d88ac137.jpg","Family Of Goats"),
  new GalleryImage("http://farm1.static.flickr.com/61/193636096_1f34d7a78d.jpg","Wooden Boat - Sailing - Port Townsend")};
  
 
 @UiField ImageGalleryWidget galleryOne, galleryTwo;
 
 public MyApp() {
  initWidget(uiBinder.createAndBindUi(this));
  galleryOne.setImages(images);
  galleryTwo.setImages(images);
 }
}

You'll notice the UiTemplate annotation above the MyAppUiBinder interface. Normally GWT will look for a UI definition file that has the same name as the parent class, however, in this case we've told GWT that the interface file is actually called MainAppInterface.ui.xml by using the annotation.

Final Test

Our final application simply has to instantiate the MyApp interface like so:

public class UIBinderExample implements EntryPoint { 
 public void onModuleLoad() {
  RootPanel.get().add(new MyApp());
 }
}

Conclusion

Hopefully this post has shown how to use some features of the GWT declarative UI, by no means does it show everything that's possible!

A complete Eclipse project with all the code from this post can be found here

Monday, September 21, 2009

Building Opera Unite Services in Java

For the last few weeks I've been experimenting with Opera Unite, due to be release in the next version of the Opera browser. Opera Unite services are built in JavaScript, however this felt like a limitation as building anything big in JavaScript alone can get a little hairy.

With this in mind I started on a few experiments to see if I could use GWT as a framework to build these services, thus allowing me to stay directly in the nice type safe world of Java.

GWT-Unite is the result of these experiments. It's a set of API's that allow easy creation of Opera Unite services without ever seeing a scrap of JavaScript! If your interested in taking a look, I've hosted it over at Google Code (gwt-unite.googlecode.com) where you'll find the source code, libaries, examples and documentation. If you have any ideas on how to make it better, why not join me!

Friday, January 30, 2009

GWT, Internet Explorer and XMLHttpRequest Caching

This morning I spent over an hour tracking down and solving a client/server communication issue which I'm going to document here, for all weary travellers who come this way. The application in question uses the GWT RequestBuilder in order to make an HTTP GET request to the server. When running in GWT Hosted mode I have a relay servlet that acts as a proxy allowing me to test the application against the real server without breaking the browser same origin policy.

The Problem

When running the application I couldn't understand why the first request retrieved the correct JSON response, but any further requests only ever returned this same original response, when in fact they should have been very different. I tried all the obvious things such as accessing the server using a browser and the server appeared to be working correctly.

I finally tracked the issue down to the fact that on Vista GWT hosted mode uses Internet Explorer as its embedded browser. Unfortunately due to some bugs (thanks to this post which gave me the required pointers), Internet Explorer will cache XMLHttpRequests if they're for the same URL. As it happens, because I'm using a relay servlet, all the requests do indeed look like they are going to the same URL, and thus IE keeps returning the same response, without ever sending the request to the server.

The Solution

The solution (at least when using hosted mode), is to change the Internet Explorer cache settings (I'm using IE 7), which can be done by selecting Tools, Options and clicking the Browser History settings button, (I'm not sure why cache settings are in browser history section!):

In the resulting dialog, chosing "Check for newer pages Every time I visit a page", resolved the issue. I would certainly recommend modifying this setting even if your not using XMLHttpRequests as I've also had issues with style sheets getting stuck in the IE cache!

Note: this appears to be a Windows only issue, on Linux GWT hosted mode uses Mozilla, although it certainly would be nice to choose either IE or Mozilla on windows!

Friday, January 02, 2009

Using Eclipse Debugger With GWT

GWT uses CSS styling in order to format rendered widgets, but since your abstracted away from the underlying DOM, it can sometimes be hard to create the exact CSS rule.  I recently created a composite GXT component and as a result couldn't quite get the CSS rule correct, (as it turns out, it was a rogue DIV element messing things up).  The following shows how to use some advanced features of the Eclipse debugger, with a GWT application running in hosted mode, in order to see the HTML that's rendered for a GWT widget.
  1. First we need to set a breakpoint at the correct position in the code.  For this we open ComplexPanel: press CTRL+SHIFT+T and enter ComplexPanel and press OK
  2. Press CTRL+O and type "add", this will show the add(Widget, Element) method, press enter to jump to it
  3. On line 86 (the adopt call) right click in the margin and choose Toggle Breakpoint Setting Breakpoint
  4. Once the breakpoint has been set, right click on the breakpoint marker (blue dot in margin) and select breakpoint properties
  5. In the breakpoint dialog, click Enable Condition : Enable Condition
  6. The enable condition allows the breakpoint to only be triggered when the condition is met.  In the Condition box, enter "this instanceof RootPanel".  This is because ComplexPanel::Add will be called for all panels, but we're only interested in the point where a widget is added to the RootPanel. Breakpoint Condition
  7. Click OK and use the GWT launcher configuration to start a hosted mode session in debug mode.
  8. When the breakpoint activates, Eclipse will change to the debug perspective, stopping at line 86:  Breakpoint Triggered
  9. Press F6 to step over the adopt call, which we need to do in order to setup the child.  (If you remember from a previous post it's only in the adopt call where the Widget::setParent is called and the whole attach process begins.) Step Over
  10. Now we need to see the child DOM HTML element which we can do with the fantastic Debug Display view.  Bring up the display view by selecting Window -> Show View -> Display
  11. The display view will open (possibly at the bottom of the screen).  The display view allows any Java code to be executed, so we'll use it to call the GWT DOM.toString method which takes an element and displays the elements DOM as a string.  Go to the display view and enter DOM followed by CTRL+SPACE which will bring up the auto complete box. Select the com.google.gwt.user.client.DOM class. Selecting DOM
  12. Finish off the call to DOM.toString as follows :  Step Over
  13. Now we can execute the statement by highlighting the whole thing and clicking on the execute selected text (or pressing CTRL+SHIFT+D): Execute Selected Statement
  14. Once executed, the DOM will be displayed : DOM Complete
  15. To carry on with your application, press F8, the program will break next time something is added to the RootPanel

Saturday, December 27, 2008

The GWT rendering process

The project I'm currently working on uses GWT and GXT and so I decided to dig into the frameworks to figure out how the both perform their magic of turning Java components into HTML elements. Since I've done the work, I thought I may as well share it incase anybody else is curious!

GWT Rendering

In order for GWT to render any component it MUST be added to the RootPanel, which is just a standard Panel component that wraps an actual existing element on the browsers HTML DOM; this can be see from the following hierarchy:

The RootPanel.get(String id) method, which will look up the specified element by id and return a RootPanel that wraps it, OR it will return a DefaultRootPanel which simply wraps the Body element (which is what you get if you call the RootPanel.get() method). The following code snippet from RootPanel.get(String) shows how all this is done:

    // Find the element that this RootPanel will wrap.
    Element elem = null;
    if (id != null) {
      if (null == (elem = DOM.getElementById(id))) {
        return null;
      }
    }

    // SNIP SNIP

    // Create the panel and put it in the map.
    if (elem == null) {
      // 'null' means use document's body element.
      rp = new DefaultRootPanel();
    } else {
      // Otherwise, wrap the existing element.
      rp = new RootPanel(elem);
    }

The process by which elements are added to this RootPanel is now the same for any standard panel, but before we get into that, we must understand two concepts in GWT regarding attachment, i.e the process by which a Widget becomes attached to the HTML DOM.

  • Logical Attachment : A component is said to be Logically Attached if it has been created (or even added to a parent), but has not been added to the physical DOM.
  • Physical Attachment : A component is physically attached when it has been added to the underlying DOM (and thus will be rendered by the browser)

Components are created using Logical Attachment (by, for example, creating and setting up new Panel objects), and then physically attached by adding them to a RootPanel. GXT extends on this idea to allow components to be lazily rendered as we'll see later. For now lets have a look at how this all works using the simple GWT Label widget.

Widget Creation

Since GWT is Java, creating a new Widget is as simple as instantiating it's constructor .i.e.

Label label = new Label("My Label");

And the constructor looks like so :

 public Label() {
    setElement(Document.get().createDivElement());
    setStyleName("gwt-Label");
  }

As we can see from the following code snippet, the label constructor calls into the special GWT DOM object in order to create a DIV element, this will be the actual element that will represent this Widget in the browser. Remember though that at this time the Element has not been physically attached to the underlying DOM, you could create thousands of these Label objects and none would currently appear in the browser.

The constructor calls the setElement method in order to inform the Widget what element it is going to use. This really calls down to the UIObject class which is the base of all, UI Objects in GWT. The element is simply registered for later use :

  protected void setElement(com.google.gwt.user.client.Element elem) {
    assert (element == null) : SETELEMENT_TWICE_ERROR;
    this.element = elem;
  }

Setting up the Widget

At this point in the process we have an empty label which isn't going to look very interesting on an HTML page so now we need to give it some text. This is done via the aptly named setText method. If we have a look at Widget.setText we can see it calls the standard setInnerText the DIV element created earlier :

  public void setText(String text) {
    getElement().setInnerText(text);
  }

Rendering the Widget

We now have a label with some text which we know is actually a DIV element with some inner text, which remember is still only Logically attached; as far as the browser is concerned our Widget doesn't currently exist. As said before, in order to physically attach the element we need to add it to a RootPanel, lets now look at the process our Label goes through when it's added.

  1. RootPanel.add is called to add the Label to the underlying browser DOM
  2. ComplexPanel.add gets called to add the Label as a child of this panel (RootPanels are after all normal panels around a well known DOM element). This logically attaches the Label as a child of the panel, then physically attaches the Label as a child of the panels DOM Element.
  3. ComplexPanel.adopt is called which calls Label.setParent() to inform the label it now has a parent
  4. Label.setParent will call the onAttach method if this parent has been physically attached to the DOM (which it will have been since the panel wraps an existing DOM element)
  5. In the case of the Label there is no onAttach implementation, the DIV element was created when the Label was created and the innerText of the DIV is set as soon as setLabel is called on the Label; therefore in the case of our simple Label example, the rendering process is complete.

The following diagram shows (or at least attempts to show), how this all hangs together:

Click for bigger image

GXT Rendering

GXT or (EXT for GWT), is the widget framework I'm working with on my current project, which changes the rendering process to provide lazy rendering of the components. GXT doesn't provide a Label component, but it does provide an Html component, so lets look at how GXT handles the rendering process.

  1. When the Html component is created, unlike the GWT Label, it DOESN'T create a DOM element, instead it acts just like a simple Java Object
  2. Html.setHtml(String) can be called at any time and, if the component hasn't been attached (rendered in GXT speak), the html is simply stored in a String field.
  3. A GXT Component extends the GWT Widget class and therefore can be added to a standard RootPanel
  4. The rendering process is the same as above, however the GXT Component.onAttach overrides the Widget.onAttach in order to perform the GXT rendering process. It's worth looking at the onAttach method in a little more detail because it solves a problem with lazy rendering of components.
  5. If you look at the previous diagram you'll see that AbsolutePanel.add(Widget) retrieves the DOM element of the component (with getElement()) and passes it to the ComplexPanel.add(Widget, Element) method. Unfortunately in GXT we don't want to create the DOM element until the onAttach method which is lower down the call stack. GXT solves this by adding a dummy DOM element if getElement is called on the widget before it's been rendered. The following code shows the important part of the getElement method:
         if (!rendered) {
          if (dummy == null) dummy = DOM.createDiv();
          return dummy;
        }
    
    The onAttach method then removes this dummy DOM element (which it calls a proxy) and calls the components render method.
  6. The components render method is the work horse of the framework and performs the following :
    • calls beforeRender()
    • Intializes plugins
    • calls createStyles()
    • calls onRender()
    • If events have been added, registers to revieve
    • Adds the base style name
    • calls afterRender()
    • Fires the Events.Render event
    Out of all of these, it's the onRender method that should be overriden by components. A component onRender method MUST call setElement otherwise on returning from the onRender method an exception will be thrown.

From this it can be seen that GXT makes the rendering process a little simpler by only requiring a component to override onRender. What's more there are times when you don't actually know what type of DOM element will represent the component until it's time to actually render it, the default GWT render process does not support this.

As an example, lets compare the GWT HTML widget with the GXT Html (camel case!) component. The GWT version needs to know the DOM component type up front, simply because setElement MUST be called during widget creation, which means the GWT HTML component is ALWAYS a DIV with the HTML as the innerHtml. GXT however allows components to defer the decision on the underlying DOM Element until render time and so the GXT Html component allows the actual parent tag type to be set at any time (before rendering) using the setTagName() method. At render time the correct component type is created and rendered.