Monday, December 31, 2007

GWT Widget Library Close to a 0.1.6 Release

There has been a lot of work going in to the GWT Widget Library lately, and I wanted to provide a preview of what it will include.

New Canvas widget

George Georgovassilis added a Canvas widget to the library that uses VML on Internet Explorer and the canvas tag on Firefox, Opera, and Safari. After the launch of the initial implementation you can expect to see incremental enhancements down the road.

Calendar Widgets

The existing CalendarPanel has had some performance improvements including one that can cut the rendering time in half. In addition to this there is a new SimpleCalendar widget that builds on the CalendarPanel by providing controls for navigating. The SimpleCalendar is accompanied by several stylesheets to make it easy to use out of the box.

Depending on the timing you may also see the addition of an EventCalendar. The EventCalendar widget will display one or more calenders with a list of events below the calendars. A single set of controls will be provided to advance the series of calenders. So for example you may display three calendars to represent the quarter, then be able to navigate forward and back full quarters.

HTMLInclude Widget

You can think of the HTMLInclude widget as the core HTML widget with one small difference, you supply the URL of the content instead of in-lining the content in your application. The benefit is that your code is no longer cluttered with long strings of HTML content, and you can change the content without needing to recompile your application.

Beyond this there has been a reasonable amount of house cleaning and bug fixing, including providing an updated Maven 2 POM file to make it easy to download and compile the library from the source.

There is no schedule, but I hope to have this released no later than the end of January. If you interested in a sneak peak please feel free to download and build from the source, the trunk is always kept in a fairly stable condition.


Library Home Page

Subversion Repository

Friday, December 28, 2007

Presentation: GWT Tools Panel

As mentioned in a prior post I had the opportunity to be a part of the GWT Tools Panel at the recent conference hosted by Peason. That session was just made available online for those unable to attend the conference.



You can find this presentation and others from the conference on YouTube.

Thursday, December 20, 2007

Testing Servlets with JUnit

In my day-to-day job I write a lot of unit tests, and I try to test everything I can. Recently though I had written a service that I was unable to test completely. One of the methods in the service had the job of sending an HTTP request to a remote server and responding with the results. For my project I used commons-httpclient to send the request.

@SuppressWarnings("unchecked")
public String sendHttpPost (String url, String queryString)
throws Exception
{
String result = null;

try {
HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url);
post.setQueryString(queryString);
client.executeMethod(post);

result = post.getResponseBodyAsString();
post.releaseConnection();
}
catch (Exception e) {
throw new Exception("post failed", e);
}

return result;
}


If you have used commons-httpclient, this is about as simple as it gets, but I still wanted to have a unit test for it. So the problem became, "how can I test this method when it requires that I hit a web site". After some searching I found that the Jetty servlet-container has a ServletTester class just for this purpose.

In my Maven 2 I included the ServletTester using the following repository and dependency information. I always use Maven 2 as allows other developers to quickly set up their IDE and download all required JARs. If you don't use Maven, you will need to manually download all of the dependencies.

<repositories>
<repository>
<id>codehaus-release-repo</id>
<name>Codehaus Release Repo</name>
<url>http://repository.codehaus.org</url>
</repository>
</repositories>

...

<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-servlet-tester</artifactId>
<version>6.1.6</version>
<scope>test</scope>
</dependency>


With this in place the next step was writing the JUnit test cases. For me I wanted to initialize the servlet-container once, then run a set of tests against it. In JUnit 4 you can use the @BeforeClass and @AfterClass annotations to mark methods that should be executed before and after all of the tests.

public class HttpPostServiceTest
{
private static ServletTester tester;
private static String baseUrl;


/**
* This kicks off an instance of the Jetty
* servlet container so that we can hit it.
* We register an echo service that simply
* returns the parameters passed to it.
*/
@BeforeClass
public static void initServletContainer () throws Exception
{
tester = new ServletTester();
tester.setContextPath("/");
tester.addServlet(EchoServlet.class, "/echo");
baseUrl = tester.createSocketConnector(true);
tester.start();

}

/**
* Stops the Jetty container.
*/
@AfterClass
public static void cleanupServletContainer () throws Exception
{
tester.stop();
}
}


The code highlighted in blue is where we start an instance of the server. I created a new instance of the ServletTester, setting the context path and adding a servlet mapping. This alone does not bind the server to a port, for that you need to call createSocketConnector(true), which binds the server to a local port and returns the URL. The port used will be a high unused port. I save an instance of the ServletTester so that I can stop the service in the @AfterClass block, and I save the baseUrl so that I can target it in my tests.

The servlet I added to the container I called EchoServlet. This servlet simply echos the parameters passed to it.

public class EchoServlet extends GenericServlet
{

@SuppressWarnings("unchecked")
@Override
public void service (ServletRequest request, ServletResponse response)
throws ServletException, IOException
{
PrintWriter out = response.getWriter();
Map<String, String[]> params =
new TreeMap<String, String[]>(request.getParameterMap());

out.println("SIZE=" + params.size());
for (Entry<String, String[]> entry : params.entrySet()) {
out.println(entry.getKey() + ":::"
+ StringUtils.join(entry.getValue(), ","));
}
}
}


The servlet takes the parameter map and creates a TreeMap out of it. The TreeMap is needed so that the parameter names are returned in sorted order. Being able to predict the order of the returned keys is required in order to test against the output of the servlet.

To finish things up, I just needed to write a unit test.

@Test
public void testPost () throws Exception
{
PostService svc = new PostService();

String res = svc.sendHttpPost(baseUrl + "/echo",
"foo=bar&baz=%25%26%3D%2F");
String[] resList = StringUtils.split(res, "\n");

assertEquals(3, resList.length);
assertEquals("SIZE=2", resList[0].trim());
assertEquals("foo:::bar", resList[1].trim());
assertEquals("baz:::%&=/", resList[2].trim());
}


After that, run the test and watch it work.

Saturday, December 15, 2007

Resistance to Change

As a programmer I have learned to embrace change, but this was not always the case. I can remember when I was once told a long time ago that I was resistant to change. At the time I felt that change was bad, it was expensive and there was in my mind no reason do so. But now I see the flip side of the coin, without change there can not be betterment.

For me changing from a Perl developer to a Java developer was a good thing. Changing from a pure development role to an architect role was also a good thing. I have found that if you want to change it can be extremely rewarding and even fun. For me I enjoy learning and employing new tools that increase my productivity and the quality of my applications, but with others I often see resistance to these changes.

Now that I am a father I see something in my son that wasn't obvious to me when I was his age. I see that he wants to learn. He wants to play with the computer, learn how to count, and he learns things because to him it is all a big game. Learning for him is fun.

To me it seems that there is some force in him that makes him want to explore and learn, and this isn't unique to just my son, all children seem to exhibit this behaviour. This makes me wonder what it is that makes us adults begin to resist change at some point in our lives, and we no longer see the fun in it.

I am not a psychiatrist, so I dare not try to explain this phenomena, but there is a reason why I am bringing this up (bear with me). I have been thinking about the tools that I have begun to employ in the work environment, and wanted to start blogging about them. All of them were resisted by at least some of our developers, but over time they began to see the benefits and now that the change had taken hold it is no longer difficult.

Some of the tools that I now live by are JUnit, Jira, Crucible, Fisheye, Subversion, and others. Some of these are free and some are not. When I blog about them I expect to see some resistance, especially for the commercial tools. In light of the expected resistance I will try to spell out how they made things better for both the developer who needs to use them and the manager who needs to understand the value proposition.

Sunday, December 09, 2007

GWT Patterns: Simplifying Structure Through Events

<narrative>
On the way back from the GWT conference I felt pretty inspired, and decided to restart work that I had done on a GWT chess application. Like most apps that I build for fun, I didn't think the whole thing through before I started. In particular I was interested in the drag-and-drop aspect of the project, so I started there. Eventually I got to the point where I could move the pieces to only valid locations, but I had inadvertently made it difficult to tie in a back-end system to control a two player game. So on the flight back from the conference the refactoring began.

One of the sticking points that I kept running into was that the interactions between classes was getting rather complex and hard to follow. For example, when a user moves (drops) a piece it is handled by the drop controller. The drop controller needs to determine if it is a valid move and if yes needs to send the move to the server. This is kinda ugly though, having the drop controller call server-side services, and I quickly ended up having "business" code all over the place. So I started thinking about how to better control the application as a whole.
</narrative>

I am a pretty avid Spring programmer and Spring has an application wide event system. It consists of three classes, ApplicationContext, ApplicationEvent, and ApplicationListener. The context is shared between all classes in the container, just like the application scope on a Java servlet. Using the context any class may register a listener, typically itself, to receive application events. Any class with access to the context may then create events and publish them to all listeners.

In Spring these events are published synchronously, meaning that the first listener needs to finish processing before the second listener gets to even see the event. This also means that the caller that published the event will block until all listeners have had a chance to handle the event. This model suits us fine for GWT since JavaScript is single-threaded anyway.

Time to look at some code, starting with the context.


import java.util.Vector;

public class ApplicationContext
{
private static Vector listeners = new Vector();

public static void addApplicationListener (ApplicationListener listener)
{
listeners.add(listener);
}

public static void removeApplicationListener (ApplicationListener listener)
{
listeners.remove(listener);
}

public static void publishEvent (ApplicationEvent event)
{
for (int i = 0; i < listeners.size(); i++) {
((ApplicationListener)listeners.get(i))
.onApplicationEvent(event);
}
}
}

In Spring the context would normally be injected into our classes, but as GWT lacks built-in support for dependency injection we simply make all of the methods static so that we can use it as a singleton. We have three methods; one to register a listener, one to unregister, and one to publish an event. Nothing fancy here, just the minimum required.

Next we need a listener interface and an abstract event base class.


public interface ApplicationListener
{
void onApplicationEvent (ApplicationEvent event);
}

public abstract class ApplicationEvent
{
}

I could have made the ApplicationEvent an interface, but my expectation that is at some point I may find it useful to add some helper methods in the future. Making it a n abstract class allows me to add functionality without altering the subclasses.

Now that we have all of the working parts it is time to start using it. In order to publish events we need to create classes that inherit the ApplicationEvent abstract class. In my case I decided to use fine-grained applications events, so I ended up with more than a few of them.

In the application I decided to have the entry-point class implement the listener interface, and registered it as a listener on start-up. In this application the entry-point class (acting as a controller) is the only the controller was listening to events published by various parts of the system.

Here are the two of the event class implementations used to create a new game or load an existing one.


public class CreateChessGameEvent extends ApplicationEvent
{
public CreateChessGameEvent () {
}
}

public class LoadChessGameEvent extends ApplicationEvent
{
private String gameId;

public LoadChessGameEvent (String gameId) {
this.gameId = gameId;
}

public String getGameId ()
{
return gameId;
}
}

Notice that the constructors of the specific events contain details that will be needed by the receiver of the events. Both of these events are triggered by clicking buttons in the user interface. Following is the code in the controller that receives the event and handles it based on the type of event.


public void onApplicationEvent (ApplicationEvent event)
{
if (event instanceof CreateChessGameEvent) {
service.createGame();
}
else if (event instanceof LoadChessGameEvent) {
service.loadGame(((LoadChessGameEvent)event).getGameId());
}
else if (...etc...) {
}
}

What isn't explicitly shown here is that service.createGame() and service.loadGame() both trigger asynchronous requests of the server. In the callbacks for each they simply send event notifications instead of handling the business logic themselves, which means the controller handles these events as well. The event used in the RPC callbacks is the ChessGameReceivedEvent, which includes the model for the specific game as part of it's properties.

So you might be thinking, why not just call the service methods directly from the button click handler and callback methods instead of sending an events back to a controller. If you are one of those people, consider this point. By using application events the user-interface and remote service calls have been completely decoupled from the controller and business logic. Decoupling is a good thing as it allows me to change the implementations of the service, user-interface, and controller independently.

Decoupling the view from the business logic results in cleaner code that is easier to maintain. In my case it simplified complex code, making it easy to refactor. For me it was a big win.

Saturday, December 08, 2007

Reminiscing the GWT Conference

As some of you may know, I had the privilege of speaking at the GWT conference hosted by Pearson Education this past week. I was part of the GWT tools panel moderated by Adam Houghton, creator of GWTFlow. The rest of the panel included Eric Clayberg of Instantiations, Ray Cromwell CTO of Timepedia, and Fred Sauer creator of the gwt-dnd library. Being part of the tools panel was great, but I think that with most conferences, the really fun part were the discussions between talks.

Some of the more notable characters there were David Geary and Billy Hoffman. David is a veteran author, with his last book being one on GWT (of course I would still recommend GWT in Action!). It was great talking with David, and his presentation was really well done. His experience shows, and he knows how to entertain a crowd. Outside of his duties he was pretty easy to spot, he was the only one wearing shorts.

Billy Hoffman, a hacker, security researcher, and recently author, gave a talk on Ajax Security. He is extremely passionate about his work, and it really showed in his presentation. He covered a ton of material, and could have covered a ton more if given more time for his presentation. In talking with Billy, he had indicated that Ajax is very scary from a security standpoint. This is partially because the code examples that you find in developer documentation are riddled with security problems. His book was the only one I picked up during the conference, and although I just started reading it, it looks like it will provide me with a lot of useful knowledge.

Some of the others there were Bruce Johnson, Ryan Dewsbury, Rob Jellinghaus, Joel Webber, Scott Blum, and the list goes on and on and on. The best art is that none of them were there to push their books, promote Google, or push their products. Instead it was about furthering GWT, finding out how GWT has solved real world problems, and providing information to those new to GWT. Each night of the conference we would hold a free-form session to discuss ideas and talk about GWT.

In between sessions I was able to talk with a lot of interesting people and see some of their GWT work. And now that I have seen some of these real products using GWT I am completely blown away with what can be accomplished with GWT. For at least a couple of them, using GWT to build their project was their second or third try at getting it to work. It was both enlightening and encouraging.

So, without going on and on, let me say a few things. First, it was fantastic to finally meet in person those who I had only known over email. Second, it was great to meet all of you who had read my book or used the GWT-WL, and had nice things to say about it. I don't do this sort of stuff for money, so it was very encouraging and makes me want to do more. Third, we need to do it again soon! The conference was fantastic and we need to do this more often. And if you didn't make it to this one I hope to meet you at the next one.