In an attempt to orient myself and my colleagues with GWT, I've been reading up on GWT, trying things out, and blogging about them here. My goal is to start with simple use cases and build on to them with more complex ones. The way it's been working so far is that each post builds on the prior one.

Friday, February 19, 2010

GWT’s Back Button and Bookmark Support

 

When we talk about an interactive web page, it means a user can do a lot of things on that single web page and, depending upon the application, the user reasonably expects that 1) the browser’s ‘Back’ button takes them to prior places they were within that same web page and 2) if the user has navigated to a particular place within page, they reasonably expect they can bookmark the current URL and return back to that page with that URL and the page will look similar to the point at which they bookmarked it. In this post, we’ll look at what GWT offers to enable an application to provide Back Button and Bookmark support.

Back Button Support

If we did nothing special to manage ‘Back’ support in the Contact Management application, the browser’s ‘Back’ button, no matter what the user had clicked on, would take the user back to the place they were before the Contact Management application. For example, the user opens their browser to their home page, www.google.com, then they go in to the Contact Management application. Then they click on Jim, then Joe, then Jane. When they clicked ‘Back’ at this point, they browser leaves the Contact Management application and returns to www.google.com. For our Contact Management application, it would be better if the ‘Back’ button in this case, returned them back through their clicks: from Jane back to Joe, and from Joe back to Jim. And only if they clicked ‘Back’ again, would they be returned to www.google.com.

The Browser’s ‘Back’ button really does nothing more than return the user to the prior URL they were on. So it makes sense that, in order for the Contact Management application to have Back support, each click from Jim to Joe to Jane will need the URL to change. This way, when the user clicks ‘Back’, the URL will go back through those previous URL’s. GWT has provided this capability with its History.newItem(String) method. When History.newItem(String) is called, the URL changes to reflect the new item. The String passed in to the method is not the entire URL, though. It is just a portion that GWT will append at the end of the URL after a ‘#’ symbol. Appending information to the existing URL after the ‘#’ symbol will make it so the browser doesn’t treat this as a new URL that needs to be requested from the server.

Here’s how it could look embedded in the click-handler of the Contact List UI Component:

	public void setContactList(Collection contacts){
this.contacts.clear();
for (final Contact contact : contacts){
final Text text = contactListView.addContact(contact.getFirstName());
text.addClickHandler(new ClickHandler() {

public void onClick(ClickEvent event) {
// when user clicks a Contact, add History item
History.newItem(contact.getFirstName());
eventBus.fireEvent(new ContactSelectedEvent(contact));
showContactAsSelected(contact);

}
});
this.contacts.put(contact, text);
}
}


Note: We haven’t seen the showContactAsSelected() in prior post, but all it does is change the style of the selected Contact to a ‘selected’ style and all other Contacts get a ‘normal’, unselected style.



Also, in order for the History class to be used the HTML host page must have a “special” iframe in it. With the iframe added for the Contact Management application, the HTML host page now looks like:



<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" language="javascript" src="com.gwtdesign.history.contactlist.ContactListTest.nocache.js"></script>
</head>
<body>
<!-- OPTIONAL: include this if you want history support -->
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
<h1>Contact List Test Page</h1>
</body>
</html>


With the special history iframe in the HTML page and the History.newItem() call from the Contact click-handler, the URL changes work! When the user clicks on ‘Jim’, the URL changes to look something like:

http://localhost:8888/com.gwtdesign.history.contactlist.ContactListTest/ContactListTest.html#contact=Jim



And then Joe:

http://localhost:8888/com.gwtdesign.history.contactlist.ContactListTest/ContactListTest.html#contact=Joe



And then Jane:

http://localhost:8888/com.gwtdesign.history.contactlist.ContactListTest/ContactListTest.html#contact=Jane



With this in place, now the user can click the ‘Back’ button without leaving the Contact Management application. Only the portion of the URL after the ‘#’ symbol will change. However, with just this use of History.newItem(), clicking ‘Back’ will not yet fully do what we want. We see the URL change as expected when we click ‘Back’, but the page doesn’t change at all to reflect the different URL’s. The page stays completely static through these ‘Back’ clicks. This is somewhat expected, since as we discussed above, a change to a URL where the only change is after the ‘#’ symbol is an indication to the Browser that it shouldn’t refresh the page with the new URL. This means, when the URL changes, it’s up to us to determine what the page should look like. And this also means we need to know when the URL changes in this way.



GWT provides a handle to the URL-changed event via the History. addValueChangeHandler(ValueChangeHandler) method. When the page loads, we can add a ValueChangeHandler. Then as the user clicks the back button, not only will the URL change based on the new items we’ve added to the History stack, but our event handler will also get called so that we can see have our code modify the page to reflect the user’s new location.



For the Contact List, we can accomplish this with some small changes and a refactor. The Contact click-handler will no longer fire the ContactSelectedEvent. It will only change the URL (i.e. call History.newItem()):



	public void setContactList(Collection contacts){
this.contacts.clear();
for (final Contact contact : contacts){
final Text text = contactListView.addContact(contact.getFirstName());
text.addClickHandler(new ClickHandler() {

public void onClick(ClickEvent event) {
History.newItem(contact.getFirstName());
}
});
this.contacts.put(contact, text);
}
}


During the ContactListPresenter’s constructor, we’ll add a History ValueChangeHandler so that the presenter is notified of URL changes. Then when the URL change is handled, at that point, we’ll raise the ContactSelectedEvent.



	// Constructor
public ContactListPresenter(ContactListView contactListView, final EventBus eventBus){
this.contactListView = contactListView;
this.eventBus = eventBus;

History.addValueChangeHandler(new ValueChangeHandler() {

public void onValueChange(ValueChangeEvent event) {
String selectedContactName = event.getValue();
if (selectedContactName == null || selectedContact.equals(“”)){
// do nothing
}else{
Contact contact = findContactByName(selectedContactName);

/*
* Prior to refactoring, this was on the click-handler.
* To provide 'Back' support, we will now do this on a URL
* change. All the click-handler does now is change the URL
* which, in turn, calls this History ValueChangeHandler.
*/
eventBus.fireEvent(new ContactSelectedEvent(contact));
showContactAsSelected(contact);
}
}
});
}


With these changes, the user can now click through various Contacts in the Contact Management application and the Back button will back the user up through those clicks!



Bookmark Support



Our Contact Management application is currently designed to display a list of Contacts on the left-hand side. In its initial state, there is no Contact selected. At this point, the user can select a Contact and the ‘Contact Details UI Component’ will display the selected Contact. If we did nothing special to add Bookmark support, the URL the user captures after their click to the selected-contact would not return them to a page where the contact was selected. It would simply return the user to the Contact List application in its initial state, having no Contact selected. For our Contact List application, it would be better if the URL the user bookmarked could return the user to a page where a particular contact was selected.



Considering what we added above for ‘Back’ support, there is a lot of overlap for what we need to get URL/Bookmark support. When the user goes in to the app initially, they are at a URL like this:

http://localhost:8888/com.gwtdesign.history.contactlist.ContactListTest/ContactListTest.html



With the ‘Back’ support we added above, they click on ‘Jim’ and the URL changes to look like this:

http://localhost:8888/com.gwtdesign.history.contactlist.ContactListTest/ContactListTest.html#Jim



For URL/Bookmark support, we now need to be able to capture the ‘Jim’ link, navigate to some random web page outside of the Contact List Application, and then be able to go back to the Contact List application with the ‘Jim’ link. With only the Back support that we’ve added, this will NOT work. Going back to the Contact List Application with the ‘Jim’ link puts the user in the initial state of the Contact List Application. The reason is that a History value-change event is not raised when the HTML host page is first loaded. Therefore, the History ValueChangeHandler we have created in our ContactListPresenter will not get called when the page first loads.



GWT has provided an API to force this History value-change event to be raised. It is the History.fireCurrentHistoryState(). This will typically be called at the end of the Entry Point’s onModuleLoad() since all the valueChangeHandlers are expected to be in place to handle the event.



By putting a call History.fireCurrentHistoryState() as the last line of our Entry Point’s onModuleLoad() method, we can see that the URL/Bookmark support is working!



Putting it all together for the Contact List, this is now approximately what happens when the user selects a Contact from the Contact List:



image



More Browser Navigation Support



In the prior sections, we made some enhancements to the Contact Management application so that we can have Back and Bookmark support. That’s good, but there’s still an issue. Even though the names in the Contact List sort of behave like links (click on them and they do what we want them to do), the names in the list don’t look like links. They just look like plain text.



We could treat this as a styling issue and make sure they have all the link styles (e.g. underline) to ensure they look like typical web links. However, doing this will still leave the Contact links missing some browser features that users commonly expect on links: Open in New Tab, Open in New Window, Copy Shortcut, etc.



Let’s make a few tweaks to the Contact List links so that these features are all available. Earlier in the document, we implemented the Contact List names as Anchors. To give them the desired behavior, we set the text on them to be the Contact’s name and put an onClick() listener on the links so we could change the page how we wanted when the user clicked. So the pseudo-HTML that gets generated sort of looks like this:



<a onClick=“showJimInContactDetail();”>Jim</a> 


By not have the href set, we lose the browser support we’re looking for to copy shortcut, open a new window, etc. The anchor doesn’t behave like a link. Specifically, the browser doesn’t even present the right-click context menu. We could in theory change it to look more like:



<a href=”javascript:showJimInContactDetail();”>Jim</a> 


Now the anchor will behave like a link in that the browser will present the right-click context menu but the navigation functions in that menu won’t work. If the user, for example, copies the shortcut of the link, all they are copying is the JavaScript call which will do nothing for them if they bookmark it and try to use it at a later date.



In order to get the browser behavior we want, the link will need to look more like this, where the HREF has the history token that our Contact Management application understands:



<a href=”#Jim”>Jim</a>


If the link looked like this and our Contact Management app continued to keep its GWT History interactions, then we’d have everything: the Back support, the Bookmark support, and the New Tab/New Window/Copy Shortcut/etc. support.



To do this, let’s have our ContactListView.addContact() return an interface on which the Presenter can do more than just add click handlers and change the text:



public interface ContactListView {
public IAnchor addContact(String contactName);
}


The IAnchor interface will extend HasClickHandlers, HasText as expected and we’ll also add a method to set an internal href:



public interface IAnchor extends HasClickHandlers, HasText {
public void setInternalHref(String anchor);
}


And the AnchorImpl will implement that method like so:



public class AnchorImpl extends Anchor {
public void setInternalHref(String anchor) {
super.setHref("#" + anchor);
}
}


Now we can go back to the ContactListPresenter and set that property on the link:



	public void setContactList(Collection contacts){
this.contacts.clear();
for (final Contact contact : contacts){
final IAnchor anchor = contactListView.addContact(contact.getFirstName());
anchor.setInternalHref(contact.getFirstName());
anchor.addClickHandler(new ClickHandler() {

public void onClick(ClickEvent event) {
History.newItem(contact.getFirstName());
}
});
this.contacts.put(contact, text);
}
}


If the user clicks on the link normally, the History.newItem() is called in the anchor’s ClickHandler and the Contact List Presenter will fire off a ContactSelectedEvent from its History.ValueChangeHandler. If the user were to right-click/New Window on the link, then the page will open using the anchor’s HREF. This re-loads the host-page with the anchor’s HREF. This means the Entry Point’s onModuleLoad() method will execute and the last part of the onModuleLoad() method will call in to GWT’s History.fireCurrentHistoryState(). At this point, the Contact List Presenter will fire off a ContactSelectedEvent from its History.ValueChangeHandler and the user will see the appropriate contact selected in their new page.



Now the links have the full browser navigation support our users would expect!



image



This technique we just used leveraged the GWT’s Anchor.setHref() and then our code made a call to History.newItem(). That was more of an illustration to progressively enhance what we already had. In fact, GWT’s Hyperlink class has some of this built in for free. We can construct the Hyperlink with a “targetHistoryToken” and it will wire up the event-handling to call History.newItem() if a user clicks on the link. Then if we used this, our ContactListPresenter would not need to add any click-handlers to the link. All it would need to do is pass the appropriate targetHistoryToken in to the Hyperlink.



Back and Bookmark Summary



In this post we looked at what the GWT framework offers an application to support the Browser’s Back button and support Bookmarking. This support is primarily provided by the through use of the following methods on the History class: addNewItem(), addValueChangeHandler(), and fireCurrentHistoryState().



Although the GWT History methods provide the underpinnings for an application to provide Back Button and Bookmark support, the way we used the History methods in this post is probably too low-level for any reasonably complex page. In the next post, we’ll discuss problems with how the History class was used in this post and also look at a ways to address those problems.

Thursday, February 18, 2010

Instance Creation and Dependency Injection and GIN

In the prior posts, we’ve taken a high-level look at the various Java classes we’d need to build the client side of an MVP Contact Management application. We saw how to build a testable ContactDetail UI component. We saw how to build a testable ContactList UI component. However, the thing that wires them together, the AppController, is not all that testable. It has code in it that looks like the following:
	private void initContactDetailPresenter(){
ContactDetailViewImpl contactDetailViewImpl = new ContactDetailViewImpl();
contactDetail = new ContactDetailPresenter(contactDetailViewImpl);
}

AppController is directly constructing a ContactDetailViewImpl and, therefore, we cannot mock the ContactDetailView in an attempt to test the AppController. One approach to solve this would be to create a factory that we could use to get the ContactDetailView implementation.

public interface AppFactory {
ContactDetailView getContactDetailView();
ContactListView getContactListView();
}

public class AppFactoryImpl implements AppFactory {
ContactDetailView getContactDetailView(){
return new ContactDetailViewImpl();
}
ContactListView getContactListView(){
return new ContactListImpl();
}
}

Now our initContactDetailPresenter() method could look like so:<

private void initContactDetailPresenter(AppFactory appFactory){
ContactDetailView contactDetailView = appFactory.getContactDetailView();
contactDetail = new ContactDetailPresenter(contactDetailView);
}

Then at test time, we could re-implement that factory so it returns a mock ContactDetailView.

public class MockAppFactory implements AppFactory{
ContactDetailView getContactDetailView(){
return createNiceMock(ContactDetailView.class);
}
ContactListView getContactListView(){
return createNiceMock(ContactListView.class);
}
}

One thing worth noting is that, as object construction goes, we’re not only creating a ContactDetailView, but we’re also injecting it in to the ContactDetailPresenter since ContactDetailPresenter has a dependency on a ContactDetailView implementation. This is DI -- dependency injection (see DI link for more information). We have used dependency injection frameworks in Java code to make each application unit testable and loosely coupled to the other units in the application. Such a framework would enable us to do things like have the ContactDetailPresenter already have the ContactDetailView injected in to it. In “normal” Java code, we might have accomplished this with the Spring dependency injection framework. However, Spring is not a GWT module so that is not available to use in client-side GWT code. It turns out that Google has developed a very capable Java dependency injection framework called Guice and this is also not a GWT module. However, it also turns out that they’ve developed a client-side equivalent to Guice which is called Gin and with Gin, we can do all the dependency injection we need.

Let’s keep looking at the Contact Management code to see what Gin will do for us. With our factory approach, we developed an AppFactory implementation which created the appropriate ContactDetailView and ContactListView implementations. Before we do anything, we’re going to change our terminology to use the word “injector” instead of factory. In an application that heavily uses DI, factories become less of a prominent feature so that’s one good reason to change terms. Also, the GIN framework and documentation and sample applications all use the term “injector” so it will be better if we are speaking the same language. The first thing Gin does is eliminate the need to implement factories. All that’s needed instead is a “module” to tersely say which implementation should be used for a particular interface.



public class AppGinModule extends AbstractGinModule{
@Override
protected void configure() {
bind(ContactListView.class).to(ContactListViewImpl.class);
bind(ContactDetailView.class).to(ContactDetailViewImpl.class);
}
}

Then our injector (previously factory) interface, via an annotation, specifies the module which has the configuration:

@GinModules(AppGinModule.class) 
public interface AppInjector extends Ginjector{
ContactDetailView getContactDetailView();
ContactListView getContactListView();
}

In our entry point, we can now call GWT.create() to have Gin return an implementation of our injector (previously factory). This injector’s methods now return the appropriate interface implementations based the module configuration:

AppInjector appInjector = GWT.create(AppGinModule.class);


This is sort of cool. We’ve defined our injector implementation with these bind().to() method calls in a configuration. Also, this configuration is fully within the core Java language, no XML files. This means it is fully type-safe, not possible to have spelling errors. This means that it is trivial using a Java IDE to find references to the ContactDetailViewImpl and see the Gin Module that is using it and how it is being used. It also means it gives us the ability to do safe refactoring if we need to rename classes, move them to different packages, etc.



But we can do more than just implementation selection. Gin can also construct ContactListPresenter and ContactDetailPresenter for us and inject its view implementation dependencies. Then our AppController doesn’t need to get the ContactDetailView from the AppInjector at all. All it needs is to do is get the ContactDetailPresenter from the AppInjector and Gin will take care of injecting the appropriate view in to the presenter.



There are two things we need to do to make this happen:



1) We need to add getContactListPresenter() and getContactDetailPresenter() methods to our AppInjector interface and



2) We need to annotate the presenters’ constructors with an @Inject annotation to let Gin know it can inject dependencies in to it.



Since ContactListPresenter and ContactDetailPresenter are not interfaces, the Gin Module configuration does not need to change at all. Also, since our AppController no longer needs to get instances of the views directly, those can be removed from the AppFactory interface. Now the interface looks like:



@GinModules(AppGinModule.class) 
public interface AppInjector extends Ginjector{
public ContactListPresenter getContactListPresenter();
public ContactDetailPresenter getContactDetailPresenter();
}


And the constructor to ContactDetailPresenter with its annotation looks like:



@Inject
public ContactDetailPresenter(ContactDetailView contactDetailView){
this.contactDetailView = contactDetailView;
}


Now the AppController can simply init its ContactDetailPresenter like so:



	private void initContactDetailPresenter(AppFactory appFactory){
contactDetail = appFactory.getContactDetailPresenter();
}


This highlights the high-level capabilities of Gin dependency injection. For the interfaces in the application, we configure the associated implementations. We annotate @Inject where we want Gin to inject dependencies and, at runtime, Gin will provide instances of classes all wired up with their dependencies injected. There are many additional capabilities for additional DI use cases. See this link for more details.



Although we saw the capabilities, we didn’t fully take advantage of them. One of the ideas of dependency injection is that factories need not be a prominent part of the application and we still have a factory sent in to the AppController so that the presenters can be acquired. The final thing we’d do here to take optimally take advantage of the DI capabilities is to have the ContactDetailPresenter and ContactListPresenter injected in to the AppController. Then all the injector needs to do is return an instance of the AppController and everything from the AppController all the way down to the views will be wired up for use.



@GinModules(AppGinModule.class) 
public interface AppInjector extends Ginjector{
public AppInjector getAppController();
}


And the entry point logic can look something like so:



	AppInjector appInjector = GWT.create(AppGinModule.class);
new AppController(appFactory).go(contacts);


With this, our Contact Management application does not create any presenters or views directly and does not managing wiring them up together. This goes a long way to creating loosely-coupled units of the overall application. Aside from that, the Gin framework has an innovative, crisp way of configuring the dependencies.



Testing



In order to get an injector implementation, our code called GWT.create(). GWT.create is a special object-creation utility in the GWT library which heavily depends upon the GWT environment. This means that, in order to create a GIN injector in a JUnit test, the JUnit must extend GWTTestCase and this is a barrier to testability since GWTTestCase is much slower than a “normal” JUnit. This does not have to be a problem as long as we consider it ahead of time. In our Contact Management AppController scenario, we removed “factories”/”injectors” out of most of our application code except the Entry Point. In that case, there really is no issue. At test time, we can wire our dependencies up however we want and we have no strong reliance on GIN in our JUnits. However, this may not be realistic in all applications and we may want to pass an injector in to parts of the application so that the Injector can operate behave more like a factory. An example of this may be a portal where the portal viewing area could display 1 of 20 different types of presenters. It may not be ideal to have GIN initialize/inject all 20 presenters when the application starts in which case, we’d want the portal to create the appropriate presenter as needed. In this case, it would be reasonable to pass an Injector in to the PortalPresenter so a injector/factory is available which can then help the PortalPresenter create the appropriate child-presenters when and if they are needed. In this case, we’ll want a GIN injector implementation that can behave how we want at test time to pass in to the PortalPresenter.



We mentioned earlier that Gin is the GWT-equivalent of Guice and at this time, it’s worth noting that the @Inject annotation we used is actually from the Java Guice library. This means that, outside of a GWT environment, we can use Guice as our DI framework. And since when testing, we do not want to be forced in to a GWT environment, Guice is a good choice to replace Gin at test-time. Guice also has the concept of a Module where we can bind implementations to interfaces and the methods/semantics are nearly comparable. For our Contact Management scenario, it could look like the following:



	public static class MockAppModule extends AbstractModule{

@Override
protected void configure() {
bind(ContactListView.class).toInstance(createNiceMock(ContactListView.class));
bind(ContactDetailView.class).toInstance(createNiceMock(ContactDetailView.class));
}
}


And here’s a tiny utility that will dynamically generate a Gin Injector implementation outside of a GWT context:



	/**
* Builds an implementation of the GinInjector which does not require a GWT runtime environment.
*


* This can be used in a JUnit that does not extend {@link GWTTestCase}.
*
* @param type of application injector to create
* @param guiceModule the Guice module
* @param appInjector type of application injector to create
* @return an implementation of the GinInjector which does not require a GWT runtime environment.
*/
public static T guiceCreate(Module guiceModule, Class appInjector){
Injector guiceInjector = Guice.createInjector(guiceModule);
return getServerSideGinInjector(guiceInjector, appInjector);
}

/**
* This creates the equivalent of a GinInjector without needing to call GWT.create().
* This can be useful for JUnits.
*
*/
public static T getServerSideGinInjector(final Injector injector, Class appInjector){
T result = (T)Proxy.newProxyInstance(Injector.class.getClassLoader(),
new Class[]{appInjector}, new InvocationHandler() {

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class returnType = method.getReturnType();
return injector.getInstance(returnType);
}
});
return result;
}



Now we can call guiceCreate() and it will create an implementation of the specified Gin Injector interface and it will be configured according the specified Guice module definition.



AppInjector mockAppInjector = guiceCreate(new MockAppModule(), AppInjector.class);
assertNotNull("The controller should be available outside of a GWT environment", mockAppInjector.getAppController());


Usage



GIN is not part of the core GWT library. It is an extension that was created and is well-supported by Google. In order to use it, a few things are needed:



1) GIN must be included in the application by inheriting it in the GWT application XML:



<inherits name="com.google.gwt.inject.Inject"/>



2) The GIN jar must be on the classpath at compile-time and run-time. The Guice and Aop Alliance jars must be on the classpath at compile and test-time.



Summary



In this post, we looked at how and why to use Dependency Injection. In particular, we looked at using GIN to loosely couple the pieces that make up our applications. Additionally, we looked at how to make this approach viable outside of a GWT environment so that we can have a good testing strategy.

Really Testing the View (Web Mode)

Although what we did in the last post was useful to see/test the view, we were not actually running through the real/production JavaScript. We were just running in “development” (a.k.a. Hosted) mode. In order to test the view through using real/production JavaScript, we need to go through a compile step, deploy that to a web server, and run the app. from there. This is called running in ‘Web Mode’. For the gory differences between Hosted and Web Mode, see this link: http://vinaytechs.blogspot.com/2009/09/google-web-toolkit-hosted-vs-web-mode.html .

To manually compile a project in Eclipse, select the ‘GWT Compile Project’ from the toolbar:

image

And we’ll get a dialog where we can usually accept the defaults:

image

After clicking ‘Compile’, GWT will do a lot of work and the Console will display details of that work. For example:

Compiling module com.gwtdesign.mvp.contactlist.ContactListTest
Compiling 6 permutations
Compiling permutation 0...
Compiling permutation 1...
Compiling permutation 2...
Compiling permutation 3...
Compiling permutation 4...
Compiling permutation 5...
Compile of permutations succeeded
Linking into C:\workspace\DesignStandards\war\com.gwtdesign.mvp.contactlist.ContactListTest.
Link succeeded
Compilation succeeded -- 27.812s


Now we can take the directory and move it in to any web server. In this screenshot, I show it moved in to an apache/tomcat web server:



image



And can hit the Tomcat-appropriate URL to see the page running the real/production Java code: http://localhost:8080/com.gwtdesign.mvp.contactlist.ContactListTest/ContactListTest.html



image



We have now run the app. in web mode and this is using the exact same code that we would deploy to a production server. Because our test relied on no server-side code, it was rather trivial to just move the HTML host page and compiled JavaScript in to any random web server that can serve up static resources. If the view has a reliance on server-side functionality, then a simple web server is not sufficient for the test and an app server will also need to be appropriately configured so the server-side of the application is available.



Debugging in Production Mode



A very cool feature of GWT is that, even in production mode, it maintains the ability to debug the JavaScript as Java. To do this, you start up the GWT app in Eclipse using ‘Debug As.. Web Application’:



image



Now, we can append the ‘gwt.codesvr’ parameter to the production URL (e.g. gwt.codesvr=127.0.0.1:9997) and that will now redirect the JavaScript execution to our Eclipse Java environment!!!



Here’s the full URL for this test (note that localhost:8080 is the Apache Tomcat server as opposed to the localhost:8888 we were previously using to run in Development mode): http://localhost:8080/com.gwtdesign.mvp.contactlist.ContactListTest/ContactListTest.html?gwt.codesvr=127.0.0.1:9997



image



With this capability, it really opens up our options. It essentially enables us to hook a Java-based debugger in to any user’s browser. Once the gwt.codesvr parameter is added to the URL, all the JavaScript is now run through our Eclipse environment. This, not only gives us the ability to troubleshoot an issue, but also the ability to test fixes since we can be code changes and they’ll be reflected on the browser in real-time. To illustrate, I’ve changed my Eclipse code to put ‘Sam’ in the list and have deployed NOTHING to my Apache Tomcat server. When I click refresh on my browser, I now see ‘Sam’ in the list:











image

Wednesday, February 17, 2010

Testing the View (Development Mode)

Now that we have a View implementation for the Contact List UI Component, it would be nice to see it rendered in a web page. We don’t have the full Contact List application ready so, at this point, we can only render the ContactListView implementation. Before starting to fill what’s needed to run this code, it will first be helpful to look at the anatomy of a GWT application:

image

For now, we’ll ignore the Production side of this diagram since we’re still filling out our development source, but feel free to refer back to it later as you look at the deployed application. To render a page that uses GWT-generated JavaScript, 4 primary things are needed in the development source:

  1. Client-side Java. This is what we’ve been building so far. The Models, Views, and Presenters were all part of the Client-Side Java which we ultimately want executed inside the browser as JavaScript.
  2. An Entry Point Java class, a class extending the GWT EntryPoint class. This is needed for any page that will execute GWT-generated JavaScript. It essentially bootstraps the page generating any initial HTML and wiring up all the event listeners to handle the user’s actions.
  3. A Module definition, an XML file that defines, among other things, what Java classes will be used to make up this JavaScript application.
  4. An HTML host page that will reference the GWT-generated JavaScript file.

To get this test started, we’ll initially build the ‘Entry Point’. For the ContactList UI Component, we have our View and Presenter implementations so the only things we need to mock for the View to be rendered are the Model objects.

	public void onModuleLoad() {

// wire up presenter with view implementation
ContactListViewImpl view = new ContactListViewImpl();
EventBus eventBus = new EventBusImpl();
ContactListPresenter presenter = new ContactListPresenter(view, eventBus);

// mock Contacts
Collection contacts = new ArrayList();
contacts.add(new ContactImpl("Jim"));
contacts.add(new ContactImpl("Joe"));
contacts.add(new ContactImpl("Jane"));

// apply contacts to view
presenter.setContactList(contacts);

// put contact list on page
RootPanel.get().add(view);
}


Next we’ll write our Module definition file. The Module definition file will be called ContactListTest.gwt.xml and looks like:



<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.0.0/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.google.gwt.user.User" />

<!-- Specify the app entry point class -->
<entry-point class='com.gwtdesign.mvp.contactlist.testui.ContactListTestEntryPoint'/>

<source path="client"/>
<source path="shared"/>
<source path="testui"/> <!-- this is where the entry point is in the test/src -->
</module>


The entry-point element references the Entry Point java class we wrote in the prior step. The source paths refer to the sub-packages with Java code that should be compiled in to JavaScript for our web page. The ‘inherits’ tag is analogous to a java import. com.google.gwt.user.User is a GWT Module that is leveraged by this Module. The ‘User’ Module must be imported in to every GWT Module. Other than what’s seen in this XML, there are a couple implicit elements not seen in the XML:




  • Because the ‘rename’ attribute was not specified for the ‘module’ element, the compiler assumes it should output the compiled JavaScript to a directory named com.gwtdesign.mvp.contactlist.ContactListTest in the web output directory. This is derived from the location and name of the Module file.


  • Because the ‘public’ element was not used, it is assumed that a directory named ‘public’ under the Module file will contain static resources for the web application.



Lastly, we need to define the HTML host file that will call the GWT-compiled JavaScript file. For our trivial test, it will look as follows:



<!DOCTYPE HTML> 
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script type="text/javascript" language="javascript" src="com.gwtdesign.mvp.contactlist.ContactListTest.nocache.js">
</script>

</head>
<body>
<h1>Contact List Test Page</h1>
</body>
</html>


Looking at the full directory structure, you’ll see that the test code is isolated to the test/src folder while the production code is in the main src folder:



image



One interesting thing when looking at the source tree is that the UI logic is contained in src/com.gwtdesign.mvp.contactlist.client yet the JUnits that test it are in a ‘test’ sub-package, test/src/com.gwtdesign.mvp.contactlist.test. This is non-standard. Typically, JUnits live in the same Java package as the Java code they test. I may find a better way to do this, but for now, this seemed like the best way to have the Entry Point and HTML host page live in the test/src. If I didn’t put the JUnits somewhere else, the <source path="client"/> in the Module file would cause the GWT-compiler to try compiling the JUnits in to JavaScript.



In Eclipse, we now can Run as... ‘Web Application’ and the page can be viewed:



image



After the Web Application starts, the ‘Development Mode’ window in Eclipse will look something like the following:



image



However, we did not put our HTML host page in the war directory, so the GWT Eclipse Plugin did not provide the appropriate URL for our test page. The URL we’ll use looks like: http://localhost:8888/com.gwtdesign.mvp.contactlist.ContactListTest/ContactListTest.html?gwt.codesvr=localhost:9997



And here is the beautiful page that we see when hitting the URL:



image



What we’ve just done is pretty cool!




  • From Eclipse, the Run As… Web Application did some magic and now we’re able to hit our web page. There is no big app server (e.g. JBoss, Weblogic, etc.) that we need to deploy to in order to run this type of test.


  • By launching the test using Debug As… Web Application, we can set a break point in any of our Java code and interactions with the web page will break in Java code as we would hope! Even though GWT compiled the Java in to JavaScript, GWT has still maintained the capability to debug the JavaScript as the Java code that we originally wrote.


  • We’ve built a test to render just one component of the Contact List application and we’ve rendered this single UI component in isolation. Not only have we rendered it in isolation, but it is all wired up to emit a ContactSelected event if the user clicks on one of the contacts. This demonstrates a few things about the design/implementation methodology:

    • Seeing this UI Component rendered in isolation with all its functionality demonstrates that this component is reusable in case we wanted to use it somewhere else. It’s clearly not coupled to the Contact Details UI Component.


    • A typical interactive web page is very complex, made up of many UI components. When a large web page is not behaving as expected, it may be quite useful to be able to render each component in isolation as a means to finding a hard-to-track down bug.





To quickly demonstrate that we can do something when a Contact is selected, I’ll tweak the Entry Point slightly by adding the following lines of code at the end:



		eventBus.addHandler(ContactSelectedEvent.TYPE, new ContactSelectedEvent.ContactSelectedEventHandler() {

public void handleEvent(ContactSelectedEvent contactSelectedEvent) {
Window.alert("Contact selected: " +
contactSelectedEvent.getSelectedContact().getFirstName());
}
});


And now we can click on ‘Jim’ and see the alert:



image



In this post, we saw how to build out our view implementation with core GWT Widgets and also learned how to manually test a UI Component in isolation.

Implementing the View

We’ve built and tested several parts of our Contact List web page yet we haven’t seen any actual HTML. Based on the responsibility of a View in MVP, we would expect the View to be where HTML is emitted. We have defined the interfaces of our views in prior posts and, in this post, we’ll start looking at the views’ implementations.

In a typical GWT application, a View is implemented by a Widget. A Widget in GWT does exactly what we described a View should do in our MVP definition. It generates HTML and support events that a user could take on that HTML. At the UI Component level, the ContactListView will be implemented by one Widget and the ContactDetailView will be implemented by another Widget. And within each of those UI Components, particular UI elements will also be implemented by Widgets.

GWT has many Widgets available in their core library. If a Widget is needed that GWT doesn’t have, there are multiple options. Most typically, though, we would either develop it ourselves or look to a third-party library that has already developed it. The GWT showcase (http://gwt.google.com/samples/Showcase/Showcase.html) demonstrates many of the Widgets that GWT delivers in its core library.

ContactListView

For our ContactListView implementation, we will extend a GWT Widget called VerticalPanel. This will layout the Contacts vertically in an HTML Table.

public class ContactListViewImpl extends VerticalPanel implements ContactListView{
public HasClickHandlers addContact(String contactName){
// TODO: implement
return null;
}
}


Immediately, we see that we have another Widget decision to make in order to return a HasClickHandlers implementation from the addContact() method. Remember that HasClickHandlers is an interface in the core GWT library and it is no coincidence that a Anchor Widget exists which implements this interface.



public class ContactListViewImpl extends VerticalPanel implements ContactListView{
public HasClickHandlers addContact(String contactName){
Anchor link = new Anchor();
link.setText(contactName);
super.add(link);
return link;
}
}

Testing the Presenter

In the prior posts, we discussed a Passive View for the purposes of testability and also talked about using an Event Bus to decouple one UI component from another. Remember that the ContactDetailPresenter functionally will be responsible for 1) displaying a selected Contact and 2) enabling a Contact to be updated. Given the design we used to build out the presenter, we should now be able to test, in isolation, that it correctly does both of those things. “In isolation” means that we want to test that the ContactDetailPresenter does what it’s supposed to do without having using a ContactListPresenter in the test. Since this is an automated, non-interactive test and we don’t have an actual browser, it will be important that we can mock the ContactDetailView. We threw around the word “mock” loosely before, but now that we’re actually writing tests, we need to be more clear about what this means and how to do it. For the tests written in this example, we will use EasyMock and that library will be implementing many methods you see in the tests such as createMock(), expect(), andReturn(), etc. It is not the scope of the post to describe EasyMock in detail, but know that having a good approach to mocking objects is a critically important aspect to writing/maintaining a solid automated test suite.

The first test validates that the ContactDetailPresenter will send a selected Contact’s first name to the ContactDetailView. The test starts out by 1) setting up its expectations that the view will receive a first name. Then 2) simulates a Contact-selection by posting a ContactSelectedEvent to the event bus and lastly 3) verifies that the View did, in fact, have the selected Contact’s first name applied to it. Here is the test:


public void testContactSelected (){
EventBus eventBus = new EventBusImpl();

String firstName = "mockFirstName";

// set up a Contact with a particular first name
Contact contact = createMock(Contact.class);
expect(contact.getFirstName()).andReturn(firstName);

// 1) set up expectation that view should be set with the first name
ContactDetailView view = createMock(ContactDetailView.class);
HasChangeHandlers mockHasChangeHandlers = createMock(HasChangeHandlers.class);
expect(view.setFirstName(firstName)).andReturn(mockHasChangeHandlers);

replay(view, contact);

ContactDetailPresenter presenter = new ContactDetailPresenter(view, eventBus);

// 2) now fire event and ensure that view is set with first name
ContactSelectedEvent contactSelected = new ContactSelectedEvent(contact);
eventBus.fireEvent(contactSelected);

// 3) verify the View had the Contact’s first name set on it
verify(view);
}


The next test validates that a user updating the first name in the Contact Detail UI will cause the ContactDetailPresenter to 1) change the first name of the Contact in the Model and 2) emit an event that the Contact was updated. To accomplish this, the test will first mock up the presenter’s dependencies to behave as needed for the test. Next, the test will simulate the first name change. Lastly, the test will verify its expectations.




public void testContactUpdated(){
String firstNameBefore = "mockFirstNameBefore";
final String firstNameAfter = "mockFirstNameAfter";

// mocks up view to have a TextInput that our test can control
ContactDetailView view = createMock(ContactDetailView.class);
final TextInput firstNameInputMock = new TextInputMock();
expect(view.setFirstName(firstNameBefore)).andReturn(firstNameInputMock);

/*
* set up a mock Contact to accept a firstName on setFirstname and
* return that same first name on getFirstName.
*/

Contact contact = createMock(Contact.class);
final Capture firstNameCapturer = new Capture();
contact.setFirstName(capture(firstNameCapturer));
expectLastCall().anyTimes();
expect(contact.getFirstName()).andAnswer(new IAnswer() {

public String answer() throws Throwable {
return firstNameCapturer.getValue();
}

}).anyTimes();

replay(contact, view);

EventBus eventBus = new EventBusImpl();

// add handler to event bus to listen for ContactUpdatedEvents
final ContactUpdatedEvent[] updatedEvent = {null};
eventBus.addHandler(ContactUpdatedEvent.TYPE,
new ContactUpdatedEvent.ContactUpdatedEventHandler() {

public void handleEvent(ContactUpdatedEvent contactUpdatedEvent) {
updatedEvent[0] = contactUpdatedEvent;
}
});

// wire up presenter with its dependencies
ContactDetailPresenter presenter = new ContactDetailPresenter(view, eventBus);
contact.setFirstName(firstNameBefore);
presenter.setContact(contact);

// simulate the first name change on the TextInput
firstNameInputMock.setText(firstNameAfter);

// verify expectations
assertNotNull("The ContactUpdatedEvent should have been emitted when the text was changed on the input", updatedEvent[0]);
assertEquals("The name of the Contact should have been changed to the new name",
firstNameAfter,
updatedEvent[0].getContact().getFirstName());
}


This is extremely powerful. We’ve tested some core aspects of our interactive web application without actually having a user interface written or even established. We have not yet built anything that resembles HTML. Given this, we can really start seeing the flexibility of this design. Since most of the Contact List UI Component works and is testable with no View, it really illustrates how little we are locked in to a particular UI layout.



In this post we looked at techniques for testing a Presenter. This is a critical component to test since it contains a lot of UI logic and, due to our MVP design pattern, it is testable.

Improving the View with Composite Interfaces

Looking back at the ContactDetailPresenter code, there is missing logic based on the initial requirements of the Contact List application. The ContactDetailPresenter does not update the Contact’s first name when the user updates the first name in the UI. In the ContactDetailPresenter.setContact() method, we set up a ChangeHandler to create a ContactUpdatedEvent and post it to the event bus. The user initiates this by updating the first name of the Contact. The problem is that no code in the ChangeHandler actually pulled the updated first name off the View and applied it to the Contact. Unfortunately, the current structure of the View provides us no means to get that updated first name. All it currently supports is the ability to listen for when the name changed via its HasChangeHandlers interface:

public interface ContactDetailView {
public HasChangeHandlers setFirstName(String firstName);
}


We set the name, but all we get back in return is the ability to add listeners for the change. We also need that returned interface to support getting the text out of the UI element where the user entered the name. We’ll introduce a new interface, TextInput, which encapsulates both of these capabilities: TextInput now has capabilities to both add change handlers and get text.



public interface TextInput extends HasChangeHandlers, HasText{

}

Note: HasChangeHandlers and HasText are both interfaces delivered in the core GWT library.


And we’ll have ContactDetailView.setFirstName() return this expanded interface.



public interface ContactDetailView {
public TextInput setFirstName(String firstName);
}


With this new TextInput interface, we can fix the issue in our Presenter and have the ChangeHandler pull the text out of the TextInput interface and apply it to the Contact:




public void setContact(final Contact contact){
final TextInput textInput = view.setFirstName(contact.getFirstName());
textInput.addChangeHandler(new ChangeHandler() {

public void onChange(ChangeEvent event) {
contact.setFirstName(textInput.getText());
eventBus.fireEvent(new ContactUpdatedEvent(contact));
}
});
}


In this post we explored a pattern to create a composite interface to give parts of a View multiple capabilities. We do this to support how a Presenter needs to interact with its corresponding View.

AppController and Event Handling

In the absence of any other object in our ContactList application, we’d send a Contact to the ContactDetailPresenter when a Contact was selected in the ContactListPresenter.

And if the user updates Joe’s first name to Joseph, we’d send a message back to the Contact List so that it displays Joseph instead of Joe.

image

And then Product Management might come along and say that the Browser Window title should reflect the selected Contact. In response, we’d add a BrowserWindowPresenter and wire things up to get that displaying what it should.

image

Everything in theory will work, but we are getting to a place where the UI components’ presenters are intertwined and dependent upon each other. ContactDetailPresenter needs a handle to ContactListPresenter and BrowserWindowPresenter in order to send them contact-updated notifications. ContactListPresenter needs a handle to ContactDetailPresenter and BrowserWindowPresenter in order to send them contact-selected notifications. It’s not too hard to imagine that, as a page gets more complex, the number of dependencies among the Presenters will grow. This means a couple things:

· This makes testing challenging. In order to test the ContactListPresenter behavior in isolation, we would need to mock the BrowserWindowPresenter and the ContactDetailPresenter.

· If we like the Contact Detail UI Component and decide it should be re-used on a different page, we’d have to do significant refactoring to decouple the Contact Detail UI Component from the Contact List UI Component and the Browser Window UI Component.

To address these dependency issues, we’ll introduce an AppController to coordinate messages between UI Components and we’ll build an Event Bus in to each presenter so that the AppController can register interest in the presenter events and can react accordingly.

With the AppController in place, the diagram now looks like so:

image

The event bus in each Presenter is how the AppController registers interest in event. Then when one presenter raises events, the AppController is notified so that it can instruct other presenter what to do. We’ve now addressed the two dependency issues raised above. We can test any presenter in isolation and we can use the Contact Details UI component in any page.

GWT Events: GWT has a built-in mechanism to do event-handling. GWT’s HandlerManager class can serve as an event bus. Presenters (or whoever) can register interest in particular events using the addHandler(EventHandler) method. After that, GwtEvents can be fired on to the HandlerManager using the fireEvent(Event) method, in which case the interested parties will be notified. GWT Events have 3 main components: a Type, an Event Definition, and an Event Handler. By use of Java generics, the Event Definition is tied to a particular Type and EventHandler. This ultimately prevents us from making mistakes like handling a particular event with the wrong event-handler.

We’ll now take a couple of the events discussed for the Contact Management application and see how the code would look using GWT. First, we’ll define the needed events, ContactUpdatedEvent and ContactSelectedEvent.

Given this, here are what the ContactUpdatedEvent and ContactSelectedEvent events could look like. The ContactUpdatedEvent will be constructed with a particular Contact and can dispatch to any ContactUpdatedEventHandler.


public class ContactUpdatedEvent extends
GwtEvent{
public Contact contact;
public ContactUpdatedEvent(Contact contact){
this.contact = contact;
}
public static final Type TYPE = new Type();
public static interface ContactUpdatedEventHandler extends EventHandler{
public void handleEvent(ContactUpdatedEvent contact);
}
@Override
protected void dispatch(ContactUpdatedEventHandler handler) {
handler.handleEvent(this);
}
@Override
public Type getAssociatedType() {
return TYPE;
}
public Contact getUpdatedContact(){
return contact;
}
}

Note: GwtEvent is a class delivered in the core GWT library. EventHandler and Type are interfaces delivered in the core GWT library.

And similarly, the ContactSelectedEvent will be constructed with a particular Contact and can dispatch to any ContactSelectedEventHandler.



public class ContactSelectedEvent extends
GwtEvent{
public Contact contact;
public ContactUpdatedEvent(Contact contact){
this.contact = contact;
}
public static final Type TYPE = new Type();
public static interface ContactUpdatedEventHandler extends EventHandler{
public void handleEvent(ContactUpdatedEvent contact);
}
@Override
protected void dispatch(ContactUpdatedEventHandler handler) {
handler.handleEvent(this);
}
@Override
public Type getAssociatedType() {
return TYPE;
}
public Contact getSelectedContact(){
return contact;
}
}


And that’s all we need to define events and event-handlers for use with each Presenter’s Event Bus. With that in place, we can now go in to our presenters and add code to post events on to the EventBus.



To accomplish this, the Contact Detail Presenter could now look like the code below. Notice it now has its own event bus and an onContactUpdated() event so the AppController can register interest in a ContactUpdatedEvent. And if the Contact is updated, it will post an event to the Event Bus telling it that a Contact was updated and the AppController will be notified and can react accordingly.



public class ContactDetailPresenter {
private ContactDetailView view;
private HandlerManager eventBus = new HandlerManager(null);
public ContactDetailPresenter(ContactDetailView view){
this.view = view;
}

public void setContact(final Contact contact){
final HasChangeHandlers hasChangeHandlers = view.setFirstName(contact.getFirstName());
hasChangeHandlers.addChangeHandler(new ChangeHandler() {

public void onChange(ChangeEvent event) {
eventBus.fireEvent(new ContactUpdatedEvent(contact));
}
});
}

public void onContactUpdated(ContactUpdatedEventHandler updatedEventHandler){
eventBus.addHandler(ContactUpdatedEvent.TYPE, updatedEventHandler);
}
}


With this in place, we can now imagine that the ContactList would take a similar approach to enable an AppController to handle a ContactSelectedEvent. Here’s some code from the App Controller that wires up the events:




public void wireUpEvents(){
contactList.onContactSelected(new ContactSelectedEventHandler() {

public void handleEvent(ContactSelectedEvent contactSelectedEvent) {
contactDetail.setContact(contactSelectedEvent.getSelectedContact());
}
});

contactDetail.onContactUpdated(new ContactUpdatedEventHandler() {

public void handleEvent(ContactUpdatedEvent contactUpdatedEvent) {
contactList.updateContact(contactUpdatedEvent.getUpdatedContact());
}
});
}


Here’s an approximate sequence showing the event-registration process:



image



And here’s an approximate sequence showing the event-handling:



image









Note on Application State: The examples in this post show event handlers being constructed with a Contact object. Depending upon the type of application being built, this may not be a good idea for all these event handlers in different Presenters to have a handle to the exact same object. It’s probably better to have application state managed in a single place and only let presenters have copies of this state. I’ll research application state some more and write a post on that when I have a pattern I’m comfortable with.











Note on changes to this post: This chapter is a version 2. I changed this chapter after reading this article http://code.google.com/webtoolkit/doc/latest/tutorial/mvp-architecture.html. In the first version, I had all UI Components listening on an application-wide event bus and there was no AppController. The ContactDetailPresenter listened for ContactSelectedEvents and would update itself when a ContactSelectedEvent was raised. This meant that the UI component was essentially built for pages that raised ContactSelectedEvents; after reading this article, I realized this coupling is unnecessary and potentially limiting. I like the AppController concept better so that it can be the thing handling events that any particular UI component raises. Now the AppController listens for the ContactSelectedEvent and simply tells the ContactDetailPresenter to present a particular Contact. The ContactDetailPresenter need to know nothing of ContactSelectedEvents. The one thing I did different from the article is that I have an event bus be wholly managed by a presenter; whereas, the article shows an application-wide event bus passed in to the presenters. I personally like the presenter-owned event bus better since the presenter simply support handlers (e.g. ContactListPresenter.onContactSelected()) only for those events it can fire. This, in my opinion, keeps the contract of the presenter more clear. This approach is similar to how Widgets deal with their events and tell its clients how, for example, they can register interest in an OnClick event.


Tuesday, February 16, 2010

Why should the View know nothing about the Model?

 

An advantage of coding in Java is that our code can be strongly-typed. Since our View represents the UI, perhaps we’d design the ContactListView to have a method to addContactToList where we pass it a strongly-typed element of the Model, Contact, and the ContactListView would, in turn, add an HTML anchor as a list item to the Contact list.


public interface ContactListView{
public void addContactToList(Contact contact);
}


But we said above that our View really shouldn’t know anything about the Model and passing Contact in to the View contradicts that. In a GWT world of strongly-typed things, why is this so? Why not pass Model objects to the View and return Model objects from the View when events are raised?



It’s mostly about testability. If we pass Model objects to the View and the UI is loosely typed, then that means the View is responsible for doing translation from the Model to the UI and vice-versa. “Translation” means logic and logic necessitates unit testing. UI is traditionally hard to test and GWT is no exception. (It’s a bit easier with GWT than other approaches, but it’s still much slower than being able to test independent of a UI.) Since UI is hard to test and the View ultimately represents the UI, the View is hard to test, also. So to maximize testability, we will give the responsibility of Model-to-UI translation to the Presenter. Although not the primary driver, there is also the possibility that leaving the Model out the View will improve reusability, the ability to use a particular View with different Models.



To ensure that our View doesn’t have to do a Model-to-UI translation, we could change our View to instead add a Contact to its contact list with a String instead of a Contact:



public interface ContactListView{
public void addContactToList(String contactFirstName);
}


Now the View->to->UI translation is trivial since we passed it data that it can trivially translate to HTML. And since it’s trivial, it’s not the end of the world if we don’t frequently regression test this aspect of the View. There’s not too much that can go wrong here. The Presenter is responsible for the binding/translation of the Model to the View and can have code like so:




public void setContactList(Collection contacts){
for (Contact contact : contacts){
contactListView.addContact(contact.getFirstName());
}
}


We can now test this translation by mocking the View and we could catch an error if, for example, we bind last name instead of first name from the Model to the View/UI.



This seems fine for sending data to the View, but how should we model events that are raised from the UI? We ultimately want to tie those events back to the Model. Going back to our example, when a user clicks on ‘Joe’, the HTML link, we ultimately want an event raised that ‘Joe’, the Contact, was clicked so that we can pass it, strongly-typed, to the ContactDetailPresenter. Since we passed a primitive String to the View, the View doesn’t know that a click on ‘Joe’ represents Joe the Contact. Remember one characteristic of our UI is to raise events and call out to do stuff. Since our UI can do this, it is reasonable that our View can do this too. In a GWT MVP world, we could accomplish this by returning a HasClickHandlers interface from the addContactToList() method. With this interface, the Presenter can add handlers for click events.




public interface ContactListView{
public HasClickHandlers addContactToList(String contactFirstName);
}


Note: HasClickHandlers is an interface delivered in the core GWT library.

Now when the Presenter does a Model->View translation, it can also add a listener/handler to click-events in a strongly-typed way. Here is some code we could now write in the ContactListPresenter. Notice that a click-handler is added for each Contact added to the view.




public void setContactList(Collection contacts){
for (final Contact contact : contacts){
HasClickHandlers hasClickHandlers = contactListView.addContact(contact.getName());

hasClickHandlers.addClickHandler(new ClickHandler() {

public void onClick(ClickEvent event) {
// do something with the strongly-typed Contact

}
});

}
}


Now our ContactListPresenter has done a full Model -> UI translation for rendering and a UI -> Model translation on event-handling. The View has no logic in it specific to the Model. (In fact, we haven’t even actually implemented our View yet.) All the View needs to do is accept UI-primitive data and raise UI-primitive events to those listening for them. And back to the testability concerns, we can unit test all the Model <-> UI translation without testing the View. This is a good thing since, as we discussed before, the View is more challenging to test.



Similarly for the ContactDetailView, it could have a View that looks like the following to the ContactDetailPresenter can listen for changes the user makes to the Contact’s first name:




public interface ContactDetailView {
public HasChangeHandlers setFirstName(String firstName);
}

Note: HasChangeHandlers is an interface delivered in the core GWT library.

And a ContactDetailPresenter could interact with it like so:




public void setContact(final Contact contact){
HasChangeHandlers changeHandlers = view.setFirstName(contact.getName());
changeHandlers.addChangeHandler(new ChangeHandler() {

public void onChange(ChangeEvent event) {
// do something with the strongly-typed Contact
}
});
}

MVP

 

The approach we’ll use to model this application is MVP, Model/View/Presenter.

Here, the Presenter sits between the Model and the View. The View knows nothing of the Presenter and the View knows nothing of the Model. This is actually a variation of MVP called Passive View (see Martin Fowler’s Passive View write-up for more details http://martinfowler.com/eaaDev/PassiveScreen.html).

For the purposes of this discussion, we’ll refer to all the functionality related to the left-hand Contact List as the ‘Contact List UI Component’ and all the functionality related to the right-hand Contact Detail as the ‘Contact Detail UI Component’. Each UI Component will have an M, a V, and a P. Within each of those UI components, we’ll explore the responsibilities and distinctions between their respective Models, Views, and Presenters. For the Contact List UI Component, we can think of it mapping to MVP in this way:

image

ContactListModel

The Model is a strongly-typed representation of the data to display in the UI Component. For both UI components, this is based on a Contact, a fairly simply bean that holds the attributes of a Contact.

ContactListView

In the MVP approach, the core responsibility of the View is to represent the user interface. User interfaces are very loosely typed. In the HTML world for our Contact List, this ultimately ends up being a String on a page, something like <a>Jim</a>, an element in the DOM, and an onClick event that can call out to do stuff.

ContactListPresenter

The ContactListModel is a strongly-typed data holder and the ContactListView is just the primitive aspects of the user interface. This leaves the rest of the responsibilities of the UI component to the ContactListPresenter:

· Translating the Model to the View for display. For example, taking the first name String from a Contact object and passing that String in to the ContactListView.

· Translating the View to the Model for updates. If for example, the user could update the user’s name directly from the Contact List, the Presenter would take the String entered and put that in to the Contact object’s first name attribute.

· Translate actions the user takes on their interface in to strongly-typed events that can be emitted out of the Presenter. What does it mean to be a strongly-typed event? Our text-based user interface can do little more than tell us that “Jim”, the String, was clicked. However, all our Java business logic really wants to deal with is meaningful objects: in this case, the Contact Model. The Presenter’s responsibility will be to convert the View action indicating “Jim, the String, was clicked” in to a Presenter event indicating that “Jim, the Contact, was clicked”.

· The ContactListPresenter will not only emit events such as “the user clicked on Jim”. It will also be listening for events emitted by other presenters in case those events need to change the View of the Contact List UI Component. For example, if the ContactDetailPresenter could emit an event that a Contact was changed, the ContactListPresenter would listen for that event so it could send appropriate parts of the updated Contact in to the ContactListView.

We’ll look at code samples later about how all these responsibilities can be fulfilled in GWT.

Design by Example

 

In the subsequent sections, we will talk about GWT design concepts through the use of a sample application.

We are trying to build an interactive web page. This means we have some display and, based on certain events, actions occur. Events are typically initiated by user interaction. Actions typically involve changing the display and/or doing an AJAX call to post/request some data.

Here’s an example of an interactive web page, a Contact List application. The interactive aspects are that 1) a user can click on a contact in the left-hand list and that will cause the Contact Details to show the selected Contact and 2) a user can update the Contact’s name in the right-hand side and it will update the list so that it shows the new name for the Contact.

image

Introduction

The upcoming set of posts are intended to discuss approaches for designing and developing interactive web pages using GWT (Google Web Toolkit). Most of this information is simply rehashed from various sources, but I’m rehashing again since 1) I didn’t see this all in one place and 2) the rehashing process gives me a better understanding of what is going on anyway.

The following are resources I used as I researched this:

http://robvanmaris.jteam.nl/2008/03/09/test-driven-development-for-gwt-ui-code
    Test driven development for GWT UI code

http://code.google.com/events/io/2009/sessions/GoogleWebToolkitBestPractices.html
    Google Web Toolkit Architecture: Best Practices For Architecting Your GWT App

http://easymock.org/Documentation.html
    EasyMock Documentation


http://martinfowler.com/eaaDev/PassiveScreen.html
    Passive View


http://vinaytechs.blogspot.com/2009/09/google-web-toolkit-hosted-vs-web-mode.html
Google Web Toolkit – Hosted vs. Web Mode

Followers