For the past eight(8) years Schalk Neethling has been working as a freelance developer under the pseudo of Volume4 and is now the president of Overt Strategy Consulting. During this period he has completed over 300 projects ranging from full web application development to complete branding. As president and lead developer of Overt Strategy Consulting, Schalk Neethling and his team has released a 100% Java standards based content management system called AlliedBridge and business document exchange and review system, called Doc-Central. Schalk Neethling is also actively involved on a daily basis in the open source, web standards and accessibility areas and is a current active member of the Web Standards Group. Schalk is also the co-founder and president of the non-profit The South Web Standards and Accessibility Group, which aims to actively educate and raise awareness of web standards and accessibility to both the developer society as well as business large and small. Schalk also has a long relationship with DZone and is currently zone leader for both the web builder, css.dzone.com, as well as the .NET zone, dotnet.dzone.com, and you can find a lot of his writing there as well as on his blog located at schalkneethling.alliedbridge.com. Schalk is constantly expanding on his knowledge of various aspects of technology and loves to stay in touch with the latest happenings. For Schalk web development and the internet is not just a job, it is a love, a passion and a life style. Schalk has posted 173 posts at DZone. View Full User Profile

GWT: Building A Model

09.22.2008
| 14021 views |
  • submit to reddit

The model layer of a GWT application has to be a little bit smarter than the model in many traditional web applications. It needs to be responsible for notifying the view layer of changes, as well as for receiving updates to its own structure. In desktop Java development, this is accomplished through the use of PropertyChangeEvents and PropertyChangeListeners that bind the data from the model to the view components. The view layer "listens" for changes to the model and updates itself accordingly, using the Observer pattern. This can be done in GWT development as well. Figure 1 shows a basic User class that we will work with. It is a simple class containing a user name and other common fields, as well as two Address objects (one shipping and one billing). To get started, we need to enable these for data binding.

Figure 1 The User and Address classes serving as the model. Notice the PropertyChangeSupport attribute, which we will use to notify the view of changes to the model beans.

Problem

We need to enable data binding to user interface elements in our model.

Solution

The basis of data binding between the model and the view is triggering events in the model that notify the view of changes, and vice versa. We will use the java.beans.PropertyChangeSupport class. This isn’t a class provided by GWT yet, but it is available as part of the GWTx project (http://code.google.com/p/gwtx/), which adds to the core Java classes provided by GWT. Listing 1 shows the User object instrumented with the PropertyChangeSupport class.

Listing 1 Using the PropertyChangeSupport class in the User object:

public class User implements IsSerializable {                          

private String username;
private String firstName;
private String lastName;
private Address billingAddress = new Address();
private Address shippingAddress = new Address();
private String password;
private String notes;
private transient PropertyChangeSupport changes =
new PropertyChangeSupport(this);

public User() {
super();
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
String old = this.firstName;
this.firstName = firstName;
changes.firePropertyChange(
"firstName", old, firstName);
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
String old = lastName;
this.lastName = lastName;
changes.firePropertyChange("lastName", old, lastName );
}

public Address getBillingAddress() {
return billingAddress;
}

public void setBillingAddress(Address billingAddress) {
Address old = this.billingAddress;
this.billingAddress = billingAddress;
changes.firePropertyChange(
"billingAddress", old, billingAddress);
}

// The rest of the getters and setters are removed for brevity.

public void addPropertyChangeListener(
PropertyChangeListener l) {
changes.addPropertyChangeListener(l);
}

public void addPropertyChangeListener(
String propertyName,
PropertyChangeListener l) {
changes.addPropertyChangeListener(
propertyName, l);
}

public void removePropertyChangeListener(PropertyChangeListener l) {
changes.removePropertyChangeListener(l);
}

public void removePropertyChangeListener(
String propertyName, PropertyChangeListener l) {
changes.removePropertyChangeListener(propertyName, l);
}

}

This gives us a model object capable of notifying the view of changes and exposing methods for attaching listeners.

Discussion

This may be a lot more code than you are used to seeing in a model bean in a traditional web application, but it is mostly boilerplate. We first need to implement IsSerializable or Serializable (the GWT marker interfaces that tell the compiler this class should be made serializable), because we want this object to move back and forth between the client and the server. This time, though, we have a nonserializable property: the PropertyChangeSupport instance changes is marked transient and isn't part of the serialized version that will be sent back and forth. It is constructed each time with the object.

Once we have the PropertyChangeSupport class, we need to instrument the setter methods to fire change events. The sequence is repetitive, but very important. First you store the current value, then you set the new value, and only after the new value is set do you fire the change event . It is critical that the change events only be fired after the instance value has been set, not at the top of the setter method. The reason for this is what happens inside the PropertyChangeSupport class.

PropertyChangeSupport (PCS) provides collections and fires change events much like the interfaces used in the previous calculator example. It also checks each call to firePropertyChange() to make sure the old and new values are different before firing the event. Figure 2 shows the execution sequence for a change event being fired and updating an element with a two-way bind.

Figure 2 The flow of property change events firing will loop if not checked by the model. If the model doesn't check the change for equality, or if the change hasn't happened yet, an infinite loop is formed.

If you called firePropertyChange() at the top of the setter method, when the last step in this sequence was reached, the current instance value on the model object would still be the same, and the whole event cycle would go into an infinite loop!

Finally, we need to provide methods on the model object for listeners to be added to the model. There are two kinds of listeners supported by the PropertyChangeSupport class. Global listeners will receive an event any time a change is fired. The listener would then look at the value returned by the call to getPropertyName() on the PropertyChangeEvent instance to decide what to do. The other type of listeners are property specific . These will only be fired if the specified property changes, and they are generally the most useful listeners. However, if you have a complex model or one that requires a lot of translation between the model data and the data needed to properly render the view elements, it can be easier to just listen for any change and reset the entire view component.

This article is excerpted from Chapter 1 of GWT in Practice, by Robert Cooper and Charlie Collins, and published in May 2008 by Manning Publications.

Published at DZone with permission of its author, Schalk Neethling.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Todd Patrick replied on Mon, 2008/09/22 - 1:44pm

Maybe I'm making this too hard. Why would a developer need the GWTx project if the Classes are already in the Java 5 API?

Osvaldo Doederlein replied on Mon, 2008/09/22 - 5:15pm in response to: Todd Patrick

@Todd: I think only the fresh-new GWT 1.5 supports Java 5...

David Of replied on Fri, 2008/09/26 - 4:28am

GWT needs both class and source code to compile into Javascript which is what GWTx provides.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.