Вы находитесь на странице: 1из 297

PALACE HOTEL SAN FRANCIsCO DECEmBER 3-6, 2007

VOICEs
ThAT mATTER CONfERENCE
GOOgLE WEB TOOLKIT

FREE eBook
Gold Sponsor

The Premiere Google Web Toolkit Conference World Class Speakers including GWT co-creators Bruce Johnson and Joel Webber Network with the community using GWT to build dynamic, feature-rich Ajax applications

Media Sponsors

Dont miss this chance to learn from the best.

Register by October 27 and save $200! www.VoicesThatMatter.com/GWT2007

VOIcES
THAT MATTER cONFERENcE
GOOGLE WEB TOOLKIT

2007 eBOOK

CONTAINING EXcERPTS FROM THE FOLLOWING BOOKS:


GOOGLE WEB TOOLKIT SOLUTIONS by David Geary and Rob Gordon GOOGLE WEB TOOLKIT APPLIcATIONS by Ryan Dewsbury ScRIPTING IN JAVA by Dejan Bosanac AjAX SEcURITY by Billy Hoffman and Bryan Sullivan ENTERPRISE AJAX by David Johnson, Alexei White, and Andre Charland THE DESIGN OF SITES by Douglas K. van Duyne, James A. Landay and Jason I. Hong EcLIPSE WEB TOOLS PLATFORM by Naci Dai, Lawrence Mandel and Arthur Ryman

VOICES THAt MAttER: Google Web Toolkit Conference eBook Copyright 2008 Pearson Education, Inc. Published by: Pearson Education 800 East 96th Street Indianapolis, IN 46240 USA Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and AddisonWesley and Prentice Hall were aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals.

N O T FO R R E S A L E

I S B N : 0 -13 -23 4 4 815

B U Y TH E b OO K TO DAY

DRAFT MANUSCRIPT
Books Available December 2007
This manuscript has been provided by Pearson Education at this early stage to create awareness for this upcoming book. IT HAS NOT BEEN COPYEdiTEd Or PrOOFrEAd YET; we trust that you will judge this book on technical merit, not on grammatical and punctuation errors that will be xed at a later stage. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. All Pearson Education books are available at a discount for corporate bulk purchases. For information on bulk discounts, please call (800) 428-5531.

Google Web Toolkit Solutions


More Cool & Useful Stuff
David Geary with Rob Gordon

Upper Saddle River, NJ Boston Indianapolis San Francisco New York Toronto Montreal London Munich Paris Madrid Cape Town Sydney Tokyo Singapore Mexico City

xviii

Google Web Toolkit Solutions

About the Authors


David Geary is the author of eight books on Java technology, including the bestselling Graphic Java 2 Series, Advanced JavaServer Pages, and Core JavaServer Faces (all from Prentice-Hall). David was a member of Suns Expert Groups for the JavaServer Pages Standard Template Library (JSTL), and JavaServer Faces (JSF) 1.0. He also was the second Apache Struts committer and the inventor of the Struts Template Library, the precursor to the popular Tiles open-source framework for composing web pages from JSP fragments. David wrote questions for Suns Web Developer Certification Exam and is the president of Clarity Training Inc., a training and consulting company focusing on server-side Java technology.

Rob Gordon is an independent consultant specializing in the design and implementation of enterprise systems. He is a former Sun developer and author of Essential JNI and coauthor of Essential JMF.

Solution 4
Viewports and Maps

Solution 1: Drag and Drop

103

When you start working with GWT, it doesnt take long before you realize that the possibilities are endless. Pretty much anything you can implement in a desktop application with frameworks like Swing or the SWT is also possible with GWT. Swing provides a handy component known as a viewport, which serves as a port onto a larger view; thus the name. Viewports are handy for all sorts of things. For example, if you wanted to create a game with a scrolling background, you might use a viewport to show a portion of your background. As the games characters approach the edges of the viewport, you could scroll the underlying background to let those characters explore other portions of your games landscape. Another use for viewports is an increasingly popular component of many websites: mapping. Google led the way with Google Maps, and nowadays many websites incorporate mapping; in fact, you can even create your own maps and share them with other web denizens at http://www.discovermachine.com. Games and maps are only two examples of the usefulness of viewports. Unfortunately, GWT does not provide a viewport out of the box, but fortunately GWT provides all of the necessary ingredients so that you can easily write your own basic viewport class in a 100 or so lines of pure Java code. Thats exactly what were going to do in this chapter. But thats not all. Starting on page xxx, we show you how to incorporate user gestures in a viewport to animate the underlying view, similar to the scrolling lists found in Apples iPhone. Features such as that are typically reserved for desktop developer wizards (or cell phones from Apple), but when youre done with this chapter, youll see that anyone can do the same with just a little math and GWT.

Stuff Youre Gonna Learn


This solution explores the following aspects of GWT: Using the AbsolutePanel class to place widgets by pixel location (page xxx) Dragging one widget inside another (page xxx) Using an event preview to inhibit browser reactions to events (page xxx)

104

Google Web Toolkit Solutions

Capturing and releasing events for a specific widget (page xxx) Changing cursors with CSS styles (page xxx) Incorporating gestures in a viewport (page xxx) Using GWT timers (page xxx) The final version of our Viewport class, listed in Listing 4.5 on page xxx, weighs in at close to 350 lines of heavily commented code. In that class, we pack a lot of GWT stuff; in fact, everything listed previously is contained in our Viewport class.

Viewports
Figure 4.1 illustrates a viewport. The top picture shows a viewport and a portion of the viewports underlying view. The bottom picture demonstrates viewport clipping, whereby the underlying view is clipped to the confines of the viewport, meaning that only the portion of the view contained in the viewport is visible.

Figure 4.1

Viewports show a portion of a component that is larger than the viewport

Figure 4.2 shows our example application, which implements an actual viewport with the map shown in Figure 4.1 as the underlying view. Figure 4.2 also shows a user dragging the map toward the top-left corner inside the viewport.

Solution 4: Viewports and Maps

105

Figure 4.2

Dragging a map contained in a viewport

Mouse Cursors and Operating Systems Different operating systems use different representations of the pointer and move cursors, so when you run the sample application, the cursors may look a little different than what you see in Figure 4.2.

Now that weve seen the example application for this solution, lets see how its put together.

Solution 4: Viewports and Maps

A General-Purpose Viewport Widget


The application shown in Figure 4.2, which is listed in Listing 4.1, is ridiculously simple because weve encapsulated all the complexity in our viewport widget.
Listing 4.1 com.gwtsolutions.client.Maps

1.package com.gwtsolutions.client; 2. 3.import com.google.gwt.core.client.EntryPoint;


continues

106

Google Web Toolkit Solutions

Listing 4.1

com.gwtsolutions.client.Maps

continued

4.import com.google.gwt.user.client.ui.*; 5.import com.gwtsolutions.components.client.ui.Viewport; 6. 7.public class Maps implements EntryPoint { 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.} } RootPanel.get().add(mapViewport); mapViewport.setView( new Image(images/land_ocean_ice.jpg)); public void onModuleLoad() { final Viewport mapViewport = new Viewport();

In the preceding listing, we create a viewport and set the view to an image showing land, water, and ice on planet Earth. Then we add the viewport to the applications root panel, and were done. Before we look at the Viewport class, lets briefly look at the files and directories contained in our application.

The Map Applications Files and Directories


Our applications associated files and directories are shown in Figure 4.3.

Figure 4.3

The map applications files and directories

Solution 4: Viewports and Maps

107

Notice that this application does not contain many files. We have the Maps class, which is our application, listed in Listing 4.1 on page xxx, a CSS stylesheet, and the map image. The Viewport class is not shown in Figure 4.3, because it resides in our Components module, which contains the custom components we developed for this book.

The Viewport Implementation


Now that weve seen the implementation of the example application and its accompanying files, lets look at a first cut of the Viewport class, listed in Listing 4.2. Later on, in A Viewports View with Animated Gestures on page xxx, we discuss the final version of the Viewport class, which incorporates user gestures and view animation.
Listing 4.2 com.gwtsolutions.client.ui.Viewport

1. package com.gwtsolutions.client; 2. 3. import com.google.gwt.user.client.DOM; 4. import com.google.gwt.user.client.Event; 5. import com.google.gwt.user.client.EventPreview; 6. import com.google.gwt.user.client.ui.AbsolutePanel; 7. import com.google.gwt.user.client.ui.FocusPanel; 8. import com.google.gwt.user.client.ui.MouseListenerAdapter; 9. import com.google.gwt.user.client.ui.Widget; 10. 11.public class Viewport extends AbsolutePanel { 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. private static EventPreview preventDefaultMouseEvents =
continues

private static final String DEFAULT_MOUSE_DOWN_CURSOR = moveCursor; private static final String DEFAULT_MOUSE_DRAG_CURSOR = pointerCursor; private final FocusPanel focusPanel = new FocusPanel(); private String mouseDownCursor = DEFAULT_MOUSE_DOWN_CURSOR; private String mouseDragCursor = DEFAULT_MOUSE_DRAG_CURSOR; private Widget view = null; private boolean dragging = false; private int xoffset, yoffset; private boolean eventPreviewAdded = false;

Solution 4: Viewports and Maps

108

Google Web Toolkit Solutions

Listing 4.2
30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. } } } }; }

com.gwtsolutions.client.ui.Viewport

continued

new EventPreview() { public boolean onEventPreview(Event event) { switch (DOM.eventGetType(event)) { case Event.ONMOUSEDOWN: case Event.ONMOUSEMOVE: DOM.eventPreventDefault(event); } return true;

public Viewport() { setStyleName(gwtsolutions-Viewport); addStyleName(hideOverflow); add(focusPanel); focusPanel.addMouseListener(new MouseListenerAdapter() { public void onMouseEnter() { DOM.addEventPreview(preventDefaultMouseEvents);

public void onMouseLeave() { DOM.removeEventPreview(preventDefaultMouseEvents);

public void onMouseDown(Widget widget, int x, int y) { addStyleName(mouseDownCursor); dragging = true; xoffset = x; yoffset = y; DOM.setCapture(focusPanel.getElement());

public void onMouseMove(Widget widget, int x, int y) { if (dragging) { removeStyleName(mouseDownCursor); addStyleName(mouseDragCursor); int newX = x + getWidgetLeft(focusPanel) - xoffset; int newY = y + getWidgetTop(focusPanel) - yoffset;

Solution 4: Viewports and Maps

109

73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112.} } } } } } } } } }); } } }

setWidgetPosition(focusPanel, newX, newY);

public void onMouseUp(Widget widget, int x, int y) { if (dragging) { dragging = false; removeStyleName(mouseDownCursor); removeStyleName(mouseDragCursor); DOM.releaseCapture(focusPanel.getElement());

public String getMouseDownCursor() { return mouseDownCursor;

public void setMouseDownCursor(String mouseDownCursor) { this.mouseDownCursor = mouseDownCursor;

public String getMouseDragCursor() { return mouseDragCursor;

public void setMouseDragCursor(String mouseDragCursor) { this.mouseDragCursor = mouseDragCursor;

Solution 4: Viewports and Maps

public Widget getView() { return view;

public void setView(Widget view) { this.view = view; focusPanel.setWidget(view);

The preceding listing is just over 100 lines of code, but that code covers a number of GWT aspects:

110

Google Web Toolkit Solutions

Using the AbsolutePanel GWT class Dragging the view inside the viewport Embedding a focus panel in an absolute panel to handle mouse events Using an event preview to inhibit the browsers reaction to mouse events Capturing events to funnel them to one particular widget Changing the mouse cursor with CSS styles Adding a default CSS style name for a custom widget Lets take a look at each of those aspects.

Using an Instance of AbsolutePanel to Place Widgets at Pixel Locations


Our viewport lets users drag the underlying view, so we need to be able to place the view at specific pixel locations. In GWT, if you need to specify pixel locations for widgets, you put them in an instance of AbsolutePanel, which, as its name suggests, lets you place its widgets at absolute pixel locations. Our Viewport class extends AbsolutePanel, as you can see on line 11 of Listing 4.2.

Dragging the View Inside the Viewport


You place widgets at specific pixel locations in an absolute panel with the AbsolutePanel.setWidgetPosition method. To drag a viewports view inside the viewport, we use that method along with some simple math that constantly updates the views position as the user drags the mouse. That method call and the corresponding math are listed on lines 7073 in Listing 4.2.

Using a Focus Panel to React to Mouse Events


The AbsolutePanel class, however, has a drawback for our purposes: It does not support mouse listeners. In GWT-speak, AbsolutePanel does not source mouse events, and to drag the view within the viewport, we need to handle mouse events. So, to handle mouse events in the viewport, we place an instance of FocusPanel, which sources mouse events, inside the absolute panel at line 45 of the Viewport class. Subsequently, at line 110, we put the view widget in the focus panel. When the user drags the view, he is really dragging the focus panel, which contains the view widget. By nesting a focus panel inside an absolute panel, we can place the view by pixel location and drag it inside the viewport. Note, however, that using an instance of FocusPanel just to handle mouse events is a somewhat heavy-handed approach. In The Viewports Use of a Focus Panel: Revisted on page xxx, we discuss an alternative implementation.

Solution 4: Viewports and Maps

111

Using an Event Preview to Inhibit the Browsers Default Reaction to Mouse Events
If you try to drag an image in an HTML page, your browser will oblige you by dragging an outline of the image. For our viewport, that browser feature is an unwanted intrusion that totally ruins our dragging effect. In general, you will often want the browser to butt out of your event handling; for example, we see the same unwanted browser intrusion when we discuss drag-anddrop in XREF. How do you convince the browser to ignore events so that you can execute your code without interference? The answer is an event preview. GWT lets you place an event preview on top of the event stack, meaning that your event preview gets first crack at every event. In addition, GWTs DOM class provides an eventPreventDefault method, that, as its name suggests, prevents the browser from exercising its default reaction to an event. In the viewports mouse listeners onMouseEnter method, on line 49, we place our event preview on the top of the event stack with a call to DOM.addEventPreview(). In the mouse listeners onMouseLeave method, on line 53, we remove the event preview from the top of the stack, which returns event handling to its normal state.

Capturing Events
When the user drags the view inside our viewport, we want to funnel mouse events solely to our focus panel. If other DOM elements in the DOM tree are also handling those mouse events, even if they handle them as no-ops, we will surely pay a performance price for that event handling. So, to increase performance, we funnel events directly to our focus panel while the user drags it. We achieve that event funneling by invoking DOM.setCapture() on line 62 when the mouse is pressed. We must, however, return event handling to normal once the user stops dragging the view. On line 82, when the user releases the mouse button, we invoke DOM.releaseCapture() so that events are no longer funneled strictly to the focus panel.

Solution 4: Viewports and Maps

Clipping the Viewports View


Because our view widget (the map) is much larger than its surrounding viewport, we must clip the view so that the only part of the view thats visible is what lies within the viewport. Clipping graphics is not trivial. It takes some math and some underlying access to the internals of whatever youre clipping, such as an image. Luckily for us, however, GWTs AbsolutePanel class automatically clips anything outside of its bounds. So to clip the viewports view, we have to do nothing other than extend AbsolutePanel in our Viewport class.

112

Google Web Toolkit Solutions

Changing the Mouse Cursor with CSS Styles


When the user clicks the mouse in our viewports view, by default, we change the cursor to a pointer cursor. We accomplish that on line 57 of Listing 4.2, by adding the pointerCursor CSS style to the viewport. When the user subsequently starts dragging the view, we set the cursor to a move cursor, by removing the pointerCursor CSS style and adding the moveCursor style, on lines 67 and 68, respectively. Both the pointerCursor and moveCursor styles are defined in the stylesheet listed in Listing 4.3. Changing mouse cursors is a fairly common occurrence in many applications. Fortunately, GWT makes it easy to accomplish.

Adding a Default CSS Style Name for a Custom Widget


In addition to adding and removing CSS styles to set the viewports mouse cursor, in we also call setStyleName() on line 42 in Listing 4.2 on page xxx and specify a style named gwtsolutions-Viewport. As we saw in the preceding section, you add CSS styles to a widget by invoking the widgets addStyleName method. All of the styles added by calling addStyleName() are applied to the widget. Conversely, you can selectively remove CSS styles by calling removeStyleName(). You specify the default style name for a widget by invoking the widgets setStyleName method. GWT automatically applies default styles when they are defined. For example, even though we dont call addStyleName(gwtsolutions-Viewport) anywhere in our application, GWT still applies that style to our viewport if the style is defined, because the call to setStyleName() designates that style as the viewports default style.

com.google.gwt.user.client.ui.MouseListener
void onMouseDown(Widget sender, int x, int y)

Is called by GWT when a mouse down event occurs in a widget to which you attach a mouse listener. The sender is the widget in which the mouse down event occurred, and the x and y coordinates are relative to that widget. For example, the window bars close button is 14 pixels wide by 14 pixels high, so the onMouseDown method for the listener attached to the close button will always be passed x and y coordinates between 0 and 13, regardless of where the close button is on the screen.

Solution 4: Viewports and Maps

113

void onMouseUp(Widget sender, int x, int y)

Is called by GWT when a mouse up event occurs in a widget to which this listener is attached. Like onMouseDown(), the sender is the widget in which the event occurred, and the x and y coordinates are relative to that widget.
void onMouseEnter(Widget sender)

Is called by GWT when the mouse enters a widget to which this listener is attached. The sender is the widget in which the event occurred.
void onMouseLeave(Widget sender)

Is called by GWT when the mouse leaves a widget to which this listener is attached. The sender is the widget in which the event occurred.
void onMouseMove(Widget sender, int x, int y)

Is called by GWT when a mouse move event occurs in a widget to which this listener is attached. Like the other MouseListener methods, the sender is the widget in which the event occurred, and like onMouseUp() and onMouseDown(), the x and y coordinates are relative to that widget.

com.google.gwt.user.client.ui.UIObject
void addStyleName(String styleName)

Adds a CSS style to a widget. One of the methods of the UIObject class, which is the classs superclass and which inherits a number of methods that all widgets find useful.
UIObject.setStyleName(String styleName)

Sets a widgets default style, which GWT automatically adds to the widget if the style is defined. You do not have to call addStyleName() to apply the style specified with setStyleName().

Solution 4: Viewports and Maps

com.google.gwt.user.client.ui.AbsolutePanel
void add(Widget w)

Adds a widget to the absolute panel. AbsolutePanel also has an add(Widget w, int x, int y) method that lets you add widgets by pixel location. This method, however, which takes no positional information, adds the specified widget as though the absolute panel were a vertical panel. If you just use add() to add widgets to an absolute panel, the absolute panel will lay out the widgets vertically.

114

Google Web Toolkit Solutions

void setWidgetPosition(Widget w, int x, int y)

Sets a widgets position by pixel location, relative to the containing absolute panel. The widget reference passed to the method must reside in the absolute panel on whose behalf the setWidgetPosition method is called.
void getWidgetLeft(Widget w)

Returns the x coordinate of a widgets left edge, relative to its enclosing absolute panel.
void getWidgetTop(Widget w)

Returns the y coordinate of a widgets top edge, relative to its enclosing absolute panel.

com.google.gwt.user.client.ui.FocusPanel
void setWidget(Widget w)

Sets the widget in an instance of FocusPanel. Instances of FocusPanel can contain only a single widget. Realize that although a focus panel can contain only a single widget, that widget can be a panel itself, which in turn may contain an unlimited number of widgets, so in practice you can add as many widgets as you want to a focus panel.

com.google.gwt.user.client.DOM
static void addEventPreview(EventPreview ep)

Adds an instance of EventPreview to the top of the event stack. Your event preview gets first crack at all eventseven before the browser sees themand you can use other DOM methods, such as DOM.eventPreventDefault() in your event preview to modify how events are handled.
static void removeEventPreview(EventPreview ep)

Removes an event preview from the event stackyou rarely want to leave an event preview on top of the event stack indefinitely.
static void setCapture(Widget w)

Is called by GWT; funnels all events to the specified widget and only that widget has access to events. This method is handy for performance-intensive activities like dragging a widget so that other widgets dont waste time handling the event.

Solution 4: Viewports and Maps

115

static void releaseCapture(Widget w)

Releases event capture and returns event handling to normal. Just as you will rarely want to leave an event preview on top of the event stack, you will rarely want to capture events for a particular widget indefinitely.

com.google.gwt.user.client.EventPreview
void EventPreview.onEventPreview(Event e)

Is called by GWT for event previews that reside atop the event stack by virtue of a call to DOM.addEventPreview(). The onEventPreview method is where you write code that typically circumvents, or modifies in some manner, normal event handling, as we did by preventing the browser from reacting to mouse dragging in Listing 4.2 on page xxx.

The Viewports Use of a Focus Panel: Revisited


In Using a Focus Panel to React to Mouse Events on page xxx, we discussed how the Viewport class uses an instance of FocusPanel to handle mouse events. That implementation works, but its a bit heavy-handed because focus panels provide additional infrastructure, such as support for dispatching focus events and keyboard navigation, which we dont need in our viewport. Because of that extra infrastructure in the FocusPanel class, an option is to implement a more lightweight panel of our own that handles mouse events and then use an instance of that panel instead of a focus panel in our viewport. Listing 4.3 shows the implementation of that lightweight panel.
Listing 4.3 com.gwtsolutions.client.ui.MousePanel

Solution 4: Viewports and Maps

1. package com.gwtsolutions.components.client.ui; 2. 3. import com.google.gwt.user.client.Event; 4. import com.google.gwt.user.client.ui.MouseListener; 5. import com.google.gwt.user.client.ui.MouseListenerCollection; 6. import com.google.gwt.user.client.ui.SimplePanel; 7. import com.google.gwt.user.client.ui.SourcesMouseEvents; 8.
continues

116

Google Web Toolkit Solutions

Listing 4.3

com.gwtsolutions.client.ui.MousePanel

continued

9. // An extension of SimplePanel that sources mouse events 10.public class MousePanel extends SimplePanel 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47.} } } public void removeMouseListener(MouseListener listener) { // If there are no mouse listeners registered with this // panel, then this method is a no-op; otherwise, remove // the specified mouse listener from the panel if (mouseListeners != null) mouseListeners.remove(listener); mouseListeners.add(listener); } public void addMouseListener(MouseListener listener) { // Lazily instantiate the mouse listener collection // when the first mouse listener is added to this // panel. if (mouseListeners == null) mouseListeners = new MouseListenerCollection(); // Give the superclass the chance to handle the event super.onBrowserEvent(event); } public void onBrowserEvent(Event event) { // Fire the mouse event to listeners, if any listeners // are currently registered with this panel if (mouseListeners != null) mouseListeners.fireMouseEvent(this, event); // Sink mouse events, which means that the GWT will // call our onBrowserEvent method whenever a mouse // event occurs in this panel sinkEvents(Event.MOUSEEVENTS); public MousePanel() { super(); implements SourcesMouseEvents { private MouseListenerCollection mouseListeners = null;

The MousePanel class extends SimplePanel and maintains a collection of mouse listeners. It also implements the SourcesMouseEvents interface and implements the two methods defined by that interface: addMouseListener() and removeMouseListener().

Solution 4: Viewports and Maps

117

The MousePanel class also sinks mouse events in its constructor. We discuss sinking events in general in more detail in XREF, but here it suffices to understand that sinking mouse events causes GWT to invoke the MousePanels onBrowserEvent() whenever a mouse event occurs in an instance of MousePanel. In the MousePanels onBrowserEvent method, we fire the mouse event to all registered listeners, by invoking the fireMouseEvent method provided by the MouseListenerCollection class. After the MousePanel class is implemented, its a simple matter to modify the Viewport class to use an instance of MousePanel instead of a FocusPanel. On line 17 of Listing 4.2 on page xxx, we replace the FocusPanel with an instance of MousePanel, and were done with that change. In fact, Listing 4.5 on page xxx shows the final version of the Viewport class, which uses an instance of MousePanel.

A Viewports View with Animated Gestures


Have you seen Apples iPhone? That phone has a lot of cool features, but one of the coolest is its ability to animate scrolling of lists. Assuming you actually have more contacts than one screen can display, you can drag your finger up or down on the phones display and the underlying list scrolls, without your intervention, until you stop scrolling by tapping your finger. Those finger drags and taps are known as user gestures. Going back to our viewport, its essential to be able to drag the view contained in our viewports. Without the ability to drag our map, for example, youd only be able to see the portion of the map that was initially displayed in the viewport, rendering maps in a viewport virtually useless. But if you want to see a place on the map thats a long way from the portion of the map thats initially visible, dragging can become a chore. You have to repeatedly move the mouse to one edge of the map, drag it to the desired edge, wheel back to the original edge, and then repeat until your desired location finally scrolls into view. Ugh. So, to make it easy to quickly drag the map over great distances, we implemented animated scrolling, very similar to what Apple has done with its iPhone. Instead of finger dragging, mouse quick-dragging accomplishes our gestures. The gesture that initiates animation of the viewports underlying view is a mouse drag that lasts for less than a specified amount of time. By default, that time is a half-second, but we made that time limit configurable. So, by default, if the user drags the viewports view for less than a half-second, we initiate the views animation. On the other hand, if the drag lasts longer than a half-second, we dont initiate the animation. To stop the scrolling animation, the user makes another gesture, which is simply a mouse click somewhere within the confines of the scrolling map. If the user accomplishes a drag in under the half-second time limit, we immediately start the scrolling animation shown in Figure 5. Notice that the map scrolls in the same direction as the drag. The user can set the map in motion simply by dragging quickly. If the animation is not desired, most likely because the location of interest is already, or nearly, in

Solution 4: Viewports and Maps

118

Google Web Toolkit Solutions

view, then the user just needs to drag a the mouse for more than half a second. Not only do we scroll in the same direction as the drag that constitutes the gesture, but we also vary the speed of the scrolling animation depending on how fast the user dragged the mouse while performing the gesture. If the drag lasted a quarter of a second and covered 100 pixels, we drag the mouse 10 times faster than a drag that also lasted for a quarter of a second but only covered 10 pixels. Of course, you cant see that in Figure 5; to check out that feature, youll have to try it out for yourself. Not only is animated scrolling a highly desirable feature and a really cool effect but it also illustrates a couple of things that you might need to implement in totally unrelated situations. For example, we use a GWT timer to perform and monitor the animation. Lets see how it works.
Figure 4.4 Animated scrolling

Solution 4: Viewports and Maps

119

From top to bottom, the map scrolls from lower-right to upper-left until the user clicks the mouse on the map. Listing 4.4 shows our updated application, which configures the maps scrolling animation.
Listing 4.4 com.gwtsolutions.client.Maps

1.package com.gwtsolutions.client; 2. 3.import com.google.gwt.core.client.EntryPoint; 4.import com.google.gwt.user.client.ui.*; 5.import com.gwtsolutions.components.client.ui.Viewport; 6. 7.public class Maps implements EntryPoint { 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26.} } RootPanel.get().add(mapViewport); Solution 4: Viewports and Maps //mapViewport.setRestrictDragHorizontal(true); //mapViewport.setRestrictDragVertical(true); // Uncomment one of the following two lines of code // to restrict dragging in the horizontal or vertical // directions mapViewport.setGesturesEnabled(true); mapViewport.setGestureThreshold(1000); mapViewport.setView( new Image(images/land_ocean_ice.jpg)); public void onModuleLoad() { final Viewport mapViewport = new Viewport();

The final version of our Viewport class lets you restrict dragging either horizontally or vertically. If you uncomment out line 21 or 22, you can see that effect. Additionally, our viewport lets you do two things with respect to animated scrolling. You can enable or disable animated scrolling, and you can also set the time threshold that distinguishes a simple drag from a gesture that initiates the scrolling animation. On line 12, we call our viewports setGestureEnabled method and specify true so that scrolling animations are enabled. That call is actually unnecessary because scrolling animations are enabled by default, but we added the call to the application so that you can easily experiment with turning animated scrolling on and off.

120

Google Web Toolkit Solutions

On line 15, we set the time threshold that distinguishes a simple drag from a gesture that initiates animated scrolling to one full second, for no other purpose than to illustrate how you can change that threshold. Now that weve seen how to optionally configure the two configurable parameters we provide for animated scrolling, lets see how we actually implemented the gesture and the animation.
Animated Viewport Scrolling Really Showcases the Power of GWT The fact that its relatively easy to implement animated scrolling similar to Apples iPhones scrolling of contacts is a tribute to GWT. By using mouse listeners, preventing the browser from reacting to mouse drags, and incorporating GWT timers, we are able to accomplish a feature that is unheard of in most Java-based web application frameworks and that rivals desktop applications built with frameworks such as the AWT or Swing.

The Final Version of the Viewport


Listing 4.5 lists the final version of our Viewport class.
Listing 4.5 The Final Version of com.gwtsolutions.client.Viewport

1. package com.gwtsolutions.components.client.ui; 2. 3. import com.google.gwt.user.client.DOM; 4. import com.google.gwt.user.client.Event; 5. import com.google.gwt.user.client.EventPreview; 6. import com.google.gwt.user.client.Timer; 7. import com.google.gwt.user.client.ui.AbsolutePanel; 8. import com.google.gwt.user.client.ui.MouseListenerAdapter; 9. import com.google.gwt.user.client.ui.Widget; 10. 11.public class Viewport extends AbsolutePanel { 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. // Defaults for time and space gesture thresholds private static final int DEFAULT_GESTURE_TIME_THRESHOLD =500; private static final int DEFAULT_GESTURE_PIXEL_THRESHOLD = 5; // Constants... private static final String DEFAULT_MOUSE_DOWN_CURSOR = moveCursor; private static final String DEFAULT_MOUSE_DRAG_CURSOR = pointerCursor;

Solution 4: Viewports and Maps

121

22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64.

// How often, in milliseconds, the animated scrolling // timer is called, and the speed factor multiplier private static final int TIMER_REPEAT_INTERVAL = 50; private static final int SPEED_FACTOR_MULTIPLIER = 20; // Member variables... // The mouse panel is the viewports lone widget. When you // drag the mouse inside the viewport, the viewport drags // the mouse panel. // The view is the mouse panels lone widget, which is // always at position (0,0) inside the mouse panel. As you // drag the mouse panel, the view goes with it. // Nesting the view inside the mouse panel makes sure we // can drag any widget inside a viewport. private final MousePanel mousePanel = new MousePanel(); private Widget view = null; // The mouse down and mouse drag cursors. You can set these // values with setter methods, but by default they are // the constants defined above. private String mouseDownCursor = DEFAULT_MOUSE_DOWN_CURSOR; private String mouseDragCursor = DEFAULT_MOUSE_DRAG_CURSOR; // Keep track of whether the user is dragging the mouse // panel (and the view), or whether we are animating // scrolling in response to a user gesture. private boolean dragging = false; private boolean timerRunning = false; // The offsets and starting values are set when the mouse Solution 4: Viewports and Maps // goes down. The offsets are used in onMouseMove() when // the user is dragging, and the starting values are used // in onMouseUp() to calculate how far, and in what // direction, the mouse moved while it was dragging. // // Time down is set in onMouseDown() and used in onMouseUp() // to calculate the elapsed time of a drag. // // Unit vector and speed factor are calculated in // onMouseUp(), and used by the timer that controls // animated scrolling. private int xoffset, yoffset;
continues

122

Google Web Toolkit Solutions

Listing 4.5
65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106.

The Final Version of com.gwtsolutions.client.Viewport

continued

private int xstart, ystart; private long timeDown; private double unitVectorX, unitVectorY; private double speedFactor; // Boolean values control whether gestures are enabled, // and whether dragging is restricted horizontally or // vertically private boolean gesturesEnabled = true; private boolean restrictDragHorizontal = false; private boolean restrictDragVertical = false; // Thresholds for user gestures. Gestures initiate // animated scrolling if the user gesture falls within // both time and space thresholds. private int gestureTimeThreshold = DEFAULT_GESTURE_TIME_THRESHOLD; private int gesturePixelThreshold = DEFAULT_GESTURE_PIXEL_THRESHOLD; // This is the timer that controls animated scrolling. It // is created in onMouseDown(). private Timer timer = null; // This event preview prevents the browser from reacting // to mouse drags while the user is dragging the mouse // panel (and its widget,the view) private EventPreview preventDefaultMouseEvents = new EventPreview() { public boolean onEventPreview(Event event) { switch (DOM.eventGetType(event)) { case Event.ONMOUSEDOWN: case Event.ONMOUSEMOVE: DOM.eventPreventDefault(event); } return true; } }; public Viewport() { // If you create a CSS class with this name, GWT // will automatically apply it to all viewports

Solution 4: Viewports and Maps

123

107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149.

setStyleName(gwtsolutions-Viewport); // Add the mouse panel to the viewport add(mousePanel); mousePanel.addMouseListener(new MouseListenerAdapter() { public void onMouseEnter(Widget sender) { // Prevent the browser from reacting to mouse drags DOM.addEventPreview(preventDefaultMouseEvents); } public void onMouseLeave(Widget sender) { // Reset the browsers event handling to normal DOM.removeEventPreview(preventDefaultMouseEvents); } public void onMouseDown(Widget widget, int x, int y) { if (isGesturesEnabled() && timerRunning) { // On a mouse down, if the timer is running, stop it. timerRunning = false; timer.cancel(); } // Change the mouse cursor when the mouse goes down // and set the dragging flag to true. addStyleName(mouseDownCursor); dragging = true; // Store the offsets of the mouse click inside the // view for later reference xoffset = x; yoffset = y; Solution 4: Viewports and Maps // Capture mouse events for the view until the mouse // is released DOM.setCapture(mousePanel.getElement()); if (isGesturesEnabled()) { // If gestures are enabled, save the time when // the mouse went down, and the coordinates of // the mouse panel at the time for later reference timeDown = System.currentTimeMillis(); xstart = getWidgetLeft(mousePanel); ystart = getWidgetTop(mousePanel);
continues

124

Google Web Toolkit Solutions

Listing 4.5
150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191.

The Final Version of com.gwtsolutions.client.Viewport


if (timer == null) {

continued

// If the timer hasnt been created, create it. timer = new Timer() { public void run() { // Calculate new X and Y locations for the // mouse panel, and reposition it. int newX = getWidgetLeft(mousePanel) - (int) (unitVectorX * speedFactor); int newY = getWidgetTop(mousePanel) - (int) (unitVectorY * speedFactor); repositionView(newX, newY); } }; } } } public void onMouseMove(Widget widget, int x, int y) { if (isGesturesEnabled() && timerRunning) { // If were doing animated scrolling, ignore // mouse move events return; } if (dragging) { // If were dragging, set the drag cursor, calculate // the new X and Y positions for the mouse panel, // and reposition it. removeStyleName(mouseDownCursor); addStyleName(mouseDragCursor); int newX = x + getWidgetLeft(mousePanel) - xoffset; int newY = y + getWidgetTop(mousePanel) - yoffset; repositionView(newX, newY); } } public void onMouseUp(Widget widget, int x, int y) { if (dragging) {

Solution 4: Viewports and Maps

125

192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234.

// If we were dragging, the mouse up stops the drag dragging = false; // Get rid of the mouse drag and mouse down cursors removeStyleName(mouseDownCursor); removeStyleName(mouseDragCursor); // Release event capture for the view. Event capture // was set when the mouse went down DOM.releaseCapture(mousePanel.getElement()); if (isGesturesEnabled()) { // If were doing animated scrolling, get the time // when the mouse went up, calculate mouse movement // and elapsed time for the drag, and the unit // vector that represents the direction of the drag long timeUp = System.currentTimeMillis(); int xend = getWidgetLeft(mousePanel); int yend = getWidgetTop(mousePanel); double deltaX = Math.abs(xend - xstart); double deltaY = Math.abs(yend - ystart); long deltaTime = timeUp - timeDown; if (deltaX > deltaY) { unitVectorX = xend < xstart ? 1 : -1; unitVectorY = (double) deltaY / (double) deltaX; unitVectorY = yend < ystart ? unitVectorY : -unitVectorY; } else { Solution 4: Viewports and Maps unitVectorX = (double) deltaX / (double) deltaY; unitVectorX = xend < xstart ? unitVectorX : -unitVectorX; unitVectorY = yend < ystart ? 1 : -1; } // If the drag was within time and space // thresholds, set the speed factor, and start // the timer that controls animated scrolling if (deltaTime < gestureTimeThreshold && (deltaX > gesturePixelThreshold || deltaY > gesturePixelThreshold)) {
continues

126

Google Web Toolkit Solutions

Listing 4.5
235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. } }

The Final Version of com.gwtsolutions.client.Viewport


speedFactor =

continued

((deltaX + deltaY) / (timeUp - timeDown)) * SPEED_FACTOR_MULTIPLIER; timerRunning = true; timer.scheduleRepeating(TIMER_REPEAT_INTERVAL); } } } } private void repositionView(int newX, int newY) { // Check to see if the view scrolled out of sight; // if so, bring it back in view if (newX > getOffsetWidth()) newX = 0; else if (newX < 0-view.getOffsetWidth()) newX = getOffsetWidth(); if (newY > getOffsetHeight()) newY = 0; else if (newY < 0-view.getOffsetHeight()) newY = getOffsetHeight(); // Reposition the mouse panel, taking dragging // restrictions into account if (isRestrictDragVertical()) setWidgetPosition(mousePanel, xstart, newY); else if (isRestrictDragHorizontal()) setWidgetPosition(mousePanel, newX, ystart); else setWidgetPosition(mousePanel, newX, newY); } });

// Property setters and getters follow... public String getMouseDownCursor() { return mouseDownCursor;

public void setMouseDownCursor(String mouseDownCursor) { this.mouseDownCursor = mouseDownCursor;

Solution 4: Viewports and Maps

127

277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319.

} public String getMouseDragCursor() { return mouseDragCursor; } public void setMouseDragCursor(String mouseDragCursor) { this.mouseDragCursor = mouseDragCursor; } public Widget getView() { return view; } public void setView(Widget view) { this.view = view; mousePanel.setWidget(view); } public void setViewPosition(int x, int y) { setWidgetPosition(mousePanel, x, y); } public int getViewLeft() { return getWidgetLeft(mousePanel); } public int getViewTop() { return getWidgetTop(mousePanel); } public boolean isRestrictDragHorizontal() { Solution 4: Viewports and Maps return restrictDragHorizontal; } public void setRestrictDragHorizontal( boolean restrictDragHorizontal) { this.restrictDragHorizontal = restrictDragHorizontal; } public boolean isRestrictDragVertical() { return restrictDragVertical; } public void setRestrictDragVertical(
continues

128

Google Web Toolkit Solutions

Listing 4.5
320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347.} } } } } } } }

The Final Version of com.gwtsolutions.client.Viewport


boolean restrictDragVertical) {

continued

this.restrictDragVertical = restrictDragVertical;

public boolean isGesturesEnabled() { return gesturesEnabled;

public void setGesturesEnabled(boolean gesturesEnabled) { this.gesturesEnabled = gesturesEnabled;

public int getGestureTimeThreshold() { return gestureTimeThreshold;

public void setGestureThreshold(int gestureTimeThreshold) { this.gestureTimeThreshold = gestureTimeThreshold;

public int getGesturePixelThreshold() { return gesturePixelThreshold;

public void setGesturePixelThreshold(int gesturePixelThreshold) { this.gesturePixelThreshold = gesturePixelThreshold;

The preceding listing incorporates four features that were not present in the original version of the class listed in Listing 4.2 on page xxx: Incorporating the drag gesture Animating scrolling in response to the drag gesture Animating scrolling in the same direction as the drag gesture Varying the speed of the scrolling animation according to how fast the user performed the gesture Lets discuss how we implemented each of those features.

Solution 4: Viewports and Maps

129

Incorporating the Drag Gesture


To distinguish between a simple drag and a gesture that initiates animated scrolling, we use Javas System.currentTimeMillis() to measure the time that elapses during a mouse drag. If gestures are enabled, we call that method the first time on line 146 in reaction to a mouse down event. Subsequently, we call System.currentTimeMillis() again on line 208 in reaction to a mouse up event. If the elapsed time is less than the gesture threshold (which remember is configurable), we initiate the animation on line 155. Pretty simple.

Animating Scrolling in Response to the Drag Gesture


We implement animated scrolling with a GWT timer. On line 152, we instantiate a Timer instance and implement its run method to perform the scrolling. When we detect the user gesture, we start the timer on line 239 by invoking Timer.scheduleRepeating(), which causes GWT to repeatedly call the timers run method at the interval we specify. That interval is 50 milliseconds, which is stored in a constant declared on line 24. Also pretty simple.

Animating Scrolling in the Same Direction as the Drag Gesture


To scroll in the same direction as the user gesture, we take a page from a mechanical engineers playbook. Mechanical engineers spend a fair amount of time figuring out how things move. One of the tricks they use to establish direction is to calculate a unit vector. A unit vector is a vector, composed of directions along both the x and y axis, that is one unit in length. Figure 4.5 illustrates a unit vector.1

Solution 4: Viewports and Maps

Figure 4.5

Unit vector

Unit vectors establish direction.


1.

If your background is mechanical engineering, you may notice that our unit vector is not a true unit vector, but its close enough that the concept applies.

130

Google Web Toolkit Solutions

The top figure illustrates some arbitrary mouse drag, which covers ground in both the x and y directions. Those distances are referred to as delta X and delta Y, respectively. The corresponding unit vector doesnt care about the magnitude of the delta X and delta Y that constitute the mouse drag; instead, its only concerned with the direction of the drag. For our viewport, we calculate a unit vector from the corresponding drag gesture on lines 216 to 227. Essentially, we divide both the delta X and delta Y values by the larger of either delta X or delta Y. For example, if delta X is 50 pixels and delta Y is 10 pixels, we wind up with a unit vector whose delta X is 1 pixel and a delta Y thats 10/50, or 0.20. We use that tuple (1, 0.20) as multiplying factors on lines 157 and 160 to move the map in the right direction.

Varying the Speed of the Scrolling Animation


If the user drags the mouse for less than the gesture threshold, which by default is 1/2 second but which is configured to 1 second in our application, we initiate animated scrolling. If the user dragged the mouse fast during that period of time, meaning the mouse cursor covered a lot of ground, then we scroll fast. If the user dragged the mouse slowly, then we scroll slowly. We calculate the speed of the scrolling animation on line 236 by adding the delta X and delta Y that the drag covered divided by the elapsed time of the drag. Since that will often be a small number, we multiply it by a constant, SPEED_FACTOR-MULTIPLIER, which we set to 20 on line 25. In practice, we found that constant to provide excellent results.

com.google.gwt.user.client.Timer
Timer.run()

Is called by GWT, either once or repeatedly, depending on whether the timer was activated with Timer.schedule() or Timer.scheduleRepeating(), respectively.
Timer.schedule(int delayMillis)

Schedules a timers run method to be called by GWT once, after the delay, in milliseconds, has elapsed.
Timer.scheduleRepeating(int periodMillis)

Schedules a timers run method to be called by GWT repeatedly, at intervals specified by the period, in milliseconds.

Solution 4: Viewports and Maps

131

Stuff We Covered in This Solution


Viewports are handy widgets that afford a view onto a portion of another widget thats larger than the viewport itself. Viewports find respectable employment in applications as far-ranging as games and mapping-related software. Its a tribute to GWT that we were able to create a viewport, complete with user gestures and animated scrolling, in a couple of thoroughly enjoyable evenings. Not only is it difficult to do the same in other Java-based web application frameworks, but with most frameworks, it is impossible without resorting to JavaScript and integrating that JavaScript with your application. Try creating a viewport by using Struts, for example. Apart from the viewport widget that we developed in this chapter, weve also explored some interesting corners of GWT, such as: changing a widgets cursor; capturing and releasing events for a specific widget; using event previews to inhibit the browsers reactions to events; and using GWT timers. That knowledge will come in handy as you construct your own components, whether or not you use them in the context of a viewport widget. In the next chapterXREFwe use our viewports to display maps that we download from Yahoo!s Maps web service, so you can see how to incorporate online web services in your GWT applications. Then, in XREF, we take dragging a bit further and create a nascent drag-and-drop framework. In XREF, we will employ many of the techniques we discussed in this chapter and a few more for good measure. As always, our goal is to expose the raw power of GWT through cool and useful widgets and let you use those techniques in your own applications. Lets continue our quest.

Solution 4: Viewports and Maps

I S B N : 0 -321- 50196 -9

B U Y TH E b OO K TO DAY

GOOgLE WEB TOOLKIt APPLICatIONS


RYAN DEWSBUrY

ISBN-13: 9780321501967 | ISBN-10: 0321501969 Paperback | 640 pages

2008 Pearson Education

UPPER SADDLE RIVER, NJ LOnDOn | M un I C H |

BOsTOn PARIs |

In D I A n A P O L I s |

SAn FR AnCIsCO | SyDnEy |

NEW YORK TOK yO |

TOROnTO |

MOnTREAL MEXICO CIT y

MADRID

CAPETOWn

SInGAPORE

DRAFT MANUSCRIPT
Books Available December 2007
This manuscript has been provided by Pearson Education at this early stage to create awareness for this upcoming book. IT HAS NOT BEEN COPYEdiTEd Or PrOOFrEAd YET; we trust that you will judge this book on technical merit, not on grammatical and punctuation errors that will be xed at a later stage. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. All Pearson Education books are available at a discount for corporate bulk purchases. For information on bulk discounts, please call (800) 428-5531.

4
Software Engineering for Ajax
Perhaps the greatest advantage of using the Google Web Toolkit to build Ajax applications is having the capability to leverage advanced software engineering. JavaScript was never meant to be used to build large applications. It lacks language features that assist in code organization and compiletime type checking. It also lacks mature tools for building large applications, such as automation, integrated development environments, debugging, and testing. This chapter looks at how to use the Java software engineering tools in GWT to build nontrivial high-quality Ajax applications.

Setting Up the Development Environment


To build applications with GWT, you need the Java Development Kit (JDK) 1.4 or greater. Many other Java tools can also assist with your development, such as an IDE like Eclipse or a build tool like Ant. All of these tools bring a lot of value to the process of building Ajax applications. It is important to note that users dont need any of these tools to use your application. They do not even need to have Java installed on their computer; they only need a reasonably modern web browser like Firefox, Internet Explorer, Safari, or Opera. The GWT compiler compiles your application so it conforms to web-standard technology.

137

138

Chapter 4

Software Engineering for Ajax

Installing the Java Development Kit


The JDK, a package provided by Sun Microsystems, includes the Java Runtime Environment (JRE), which is required to run Java programs on your computer, and command line developer tools which let you compile Java classes to create code that can run. The JDK is on Suns web site at http://java.sun.com/javase/downloads. You can choose from several options to download, but the minimum you need is the JDK without anything else bundled. Some options come with NetBeans or Java EE, but these are not required. There is also a download option for JRE, but this does include the developer tools that you need. Once you download the JDK (approximately 50MB), you need to install it. On Windows, the download is an executable file that runs the installation. Install the JDK with all the default options.

Installing the Google Web Toolkit


The GWT complements the JDK by adding the ability to compile your Java code to JavaScript so that it can run in a web browser without the Java Runtime Environment. Think of the GWT as another compiler to run Java on a new platformyour web browser. It also provides a hosted mode browser that lets you take advantage of Javas powerful debugging features, just like you would debug a normal Java application. JavaScript debugging tools are primitive compared to what Java and GWT allows you to do. You can find the Google Web Toolkit SDK at http://code.google.com/webtoolkit/ download.html. On Windows, the GWT zip file is approximately 13MB. After you download it, extract the file to your preferred installation directory. On Mac and Linux you can extract the download using this tar command:
tar xvzf gwt-mac-1.3.3.tar.gz

Lets look inside the distribution. The following list gives you a brief overview of the important files that come with GWT.

Setting Up the Development Environment

139

gwt-user.jar This is the GWT library. It contains the Java classes that you use to build your application with GWT. Your application uses this file when you run it in hosted mode, but this file is not used when your application is deployed, since your application code and the code used in this file are translated to JavaScript.

gwt-servlet.jar This stripped down version of gwt-user.jar has the classes required for the server side of your application. It is much smaller than gwt-user.jar and better for deployment since it does not contain the GWT classes that are required for hosted mode.

applicationCreator This script produces the files required to start a GWT application. The generated files produce a runnable bare-bones GWT application.

projectCreator This script generates project files for an Eclipse GWT project. junitCreator This script generates a starter test case along with scripts that start the tests in web mode and hosted mode.

i18nCreator This script generates an interface based on a properties file for internationalizing an application.

With only the JDK and GWT installed, you can write, run, and compile web-based applications. For convenience, you should put the GWT installation directory on your path so that you can call the GWT scripts without specifying the full installation path each time. For example, if you installed GWT to c:\code\gwt (this is a Windows path; for Mac and Linux you would similarly use your install path), you would add this to your PATH variable. Then at a command line you can run the applicationCreator script inside your application directory without specifying the scripts full path, as shown in Figure 4-1.

140

Chapter 4

Software Engineering for Ajax

Figure 41. Running the applicationCreator script for a GWT project

Running this script creates the application named HelloWorld in the current directory. It also generates scripts that let you run the application. You can run this application by just typing the following line:
HelloWorld-shell

Running this generated script causes GWT to load its hosted browser, which in turn loads the generated application. The hosted browser displays the default generated application, as illustrated in Figure 4-2. You can also compile the application so that it can be used in a standard browser using the generated HelloWorld-compile script, as seen in Figure 4-3. The compile script builds the HTML and JavaScript files, which you need to deploy the application, and copies them to the www directory in your application directory, as shown in Figure 4-4. The generated application can be run in any browser by simply loading the host file. In this HelloWorld application, the host file is named HelloWorld.html. Loading this file in Firefox, as shown in Figure 4-5, results in the same application as in GWTs hosted browser in Figure 4-2, with the major difference being the lack of any Java dependency. So you can see that the minimum environment for building web applications with GWT is small, only requiring GWT and the JDK to be installed. However, youll be able to speed up the development process by using

Setting Up the Development Environment

141

Figure 42. Running the default generated project in hosted mode

Figure 43. Compiling the project from the command line

Figure 44. The files generated from compiling a GWT project

142

Chapter 4

Software Engineering for Ajax

Figure 45. The default project compiled and running in Firefox

many of the available Java tools. For example, an IDE like Eclipse is usually used to speed up Java development.

Installing Eclipse
Eclipse is an open source IDE developed in Java and supported by major technology companies including IBM. An IDE allows you to write, organize, test, and debug software in an efficient way. There are many IDEs for Java, and you can use any of them for GWT development. If you do not have a Java IDE installed, I suggest using Eclipse since it works very well and has support with the GWT scripts to help integration. Eclipse lets you write, organize, test, and debug your GWT Ajax applications in a productive way. It has great support for the Java language, including refactoring and content assist.1 You can develop using many languages through plugins with Eclipse by taking advantage of Eclipses rich plugin framework, but the most widely used language is Java. You can find the Eclipse download here at www.eclipse.org/downloads.

1. Content assist is an Eclipse feature that suggests or completes what you are currently typing. It automatically appears, and you can activate it when needed by pressing Ctrl+Spacebar.

Adding Projects to Eclipse

143

Select the Eclipse SDK from this page. After you download the file (approximately 120MB), extract the file to your preferred installation directory. On Windows, the default location for the file eclipse.exe is in the root of the installation directory; you may want to create a shortcut to the file since you will be using it frequently to edit and debug your code.

Adding Projects to Eclipse


When you first load Eclipse, you are prompted by the dialog box shown in Figure 4-6 for the workspace location. This is the location on your computer that will hold your projects.

Figure 46. Loading a workspace in Eclipse

Figure 4-6 shows setting the workspace to C:\Projects and selecting the check box to save this as the default workspace, so the next time Eclipse opens this workspace is automatically loaded. Since this is a new workspace, when the main Eclipse window loads it will not have any projects listed in its Package Explorer. At this point we could start building a project manually in Eclipse for the HelloWorld application built earlier in this chapter, but GWT gives us a shortcut with the projectCreator script shown in Figure 4-7. This creates an empty project that references GWT and can be easily loaded into Eclipse. To load the GWT project into Eclipse, choose File > Import to display the Import dialog box, shown in Figure 4-8.

144

Chapter 4

Software Engineering for Ajax

Figure 47. flag

Creating a project with the projectCreator script and the -eclipse

Figure 48. Step 1 of importing a generated GWT project into Eclipse

In the Import dialog, select Exiting Projects into Workspace and then click Next. The next page of the Import dialog, shown in Figure 4-9, lets you select the projects you want to import. In this dialog you first need to select the location of your project files. The dialog then presents the list of possible projects that you can import. Figure 4-9 shows the GwtApps project that we created with the GWT projectCreator script. Make sure this project is checked and then click Finish.

Adding Projects to Eclipse

145

Figure 49. Step 2 of importing a generated GWT project into Eclipse

At this point Eclipse loads the project into the Eclipse workspace, and the HelloWorld application is listed under Package Explorer, as show in Figure 4-10, since it was generated in the Projects directory. You can add other applications to this project using the application Creator script, but since were in Eclipse now we can take advantage of the -eclipse option with the script. When the HelloWorld application was run this option was not specified, so we do not have any Eclipse-specific files that allow you to launch the application from Eclipse. So lets run the applicationCreator script again, this time specifying the -eclipse option, as shown in Figure 4-11. If youre creating a new application for use in Eclipse, you do not need the -overwrite option. This example used this option to overwrite the previously generated application, which did not have Eclipse support. Notice in Figure 4-11 that the new file HelloWorld.launch was created. This launch

146

Chapter 4

Software Engineering for Ajax

Figure 410. The generated GWT project in the Eclipse IDE

Figure 411. Creating an application for use in Eclipse

file allows you to select the Debug or Run command options for the HelloWorld application inside Eclipse. To see this change in Eclipse, refresh your project (right-click on the project and select Refresh), and then run the HelloWorld application in Debug mode by clicking on the Debug icon (see the bug icon on the toolbar in Figure 4-12). If your application isnt listed in the debug drop-down box, which shows a list of recently debugged configurations, youll need to click Debug in the drop-down menu to load the Debug dialog. Youll find the launch configuration for the HelloWorld application under Java Application. The application will load in GWTs hosted mode browser, and you can interact with it while still being connected to the Eclipse IDE. This means

Writing Java Code in Eclipse

147

Figure 412. Running a GWT application in the Eclipse debugger

you can set breakpoints, change code, and perform other Eclipse functions while your application is running. The ability to do this shortens the code-test cycle dramatically and its ease promotes heavy testing. Attaching GWT development to Eclipse, or any other Java IDE, is a giant step forward for Ajax application development. Lets look at some of the details of writing code with Eclipse.

Writing Java Code in Eclipse


Eclipse has many tools for writing Java code that provide hints and constraints on what is possible, shortcuts for common tasks, and refactoring functions for large code changes. Of course, you dont have to use these tools to produce Ajax applications with GWT, but they make writing Java code a lot easier.

Creating Classes in Eclipse


First, lets look at Eclipses tools for creating classes. Eclipse lets you create new classes or interfaces by clicking on the New Class icon on the top toolbar (shown in Figure 4-13). After clicking on the New Class icon, a dropdown menu presents a list of options. For a new class you need to click Class in the drop-down menu. Clicking this icon displays a New Java Class dialog box that prompts you for the information required to create a class. This method is faster than writing a Java class file from scratch and it ensures that everything

148

Chapter 4

Software Engineering for Ajax

Figure 413. Creating a new class

required to be in the file will be there and will be correct. Notice in Figure 4-13 that the com.gwtapps.examples.client package is listed. This is where the new class will go. When the New Java Class dialog appears, it displays this package as the default package.

Figure 414. The New Java Class dialog in Eclipse

Writing Java Code in Eclipse

149

Figure 415. The new Java class in the Eclipse IDE

In this dialog, the name HelloWorldView is specified as the class name for the new class. The superclass is set to Composite. Clicking Finish creates the file and a usable Java class inside, as shown in Figure 4-15. Actually, the new Java class isnt quite usable yet. Weve specified a superclass that doesnt exist. Notice how Eclipse has unobtrusive indicators that let you know something is wrong. The Package Explorer has an X in a red square on the new Java file and on every parent node in the tree up to the project. If we had the project node closed, we would still know that there is an error somewhere in the project. Eclipse also displays a problems list at the bottom that shows a list of errors and warnings in the workspace. It also has the new problems listed. Double-clicking on any of the errors in this list brings you directly to the location of the error in an Eclipse Editor window. In this case there are two errors and the Editor window for the new Java class file is open. Inside the Editor window you can see a further indication of errors. On the right side of the Editor window red marks represent the location of the error within the file. The file representation for this vertical space is the same scale as the vertical scroll bar. So if this was a bigger file and there were errors, you could

150

Chapter 4

Software Engineering for Ajax

quickly locate them by moving the scrollbar to the location of one of the red marks to see the error in the Editor window. Inside the Editor window, error icons display on the left side and the actual code producing the error has a jagged red underline. Furthermore, when you hover the mouse over the code with the error, a tooltip displays an error message, in this case The import Composite cannot be resolved. The problem is that we selected just the simple class name as the superclass in the New Java Class dialog, but Eclipse requires the full class name. Often its hard to remember the full class name for a class, but Eclipse helps us here as well. We can have Eclipse automatically suggest the full class name by clicking on the error and selecting the Source > Add Import command, as shown in Figure 4-16.

Figure 416. Automatically adding a Java import

Alternatively, you could use the keyboard shortcut Ctrl+Shift+M to run the Add Import command. Eclipse automatically adds the required import information. In situations where there is more than one matching import, Eclipse presents you with a choice, as shown in Figure 4-17.

Writing Java Code in Eclipse

151

Figure 417. Eclipse presents a list of matching import packages

Choosing the GWT Composite class as the import fixes the errors and all of the error indications go away. Eclipse provides this type of early warning of errors for any compile-time errors instantly, instead of having to wait until you compile to get this feedback, as is typical with typed languages. Eclipse updates the IDE with this information as you develop, so you can catch errors immediately after they are created.

Using the Eclipse Java Editor


Now lets look at some of the unique features of the Eclipse Java editor. Well start by adding some code to the constructor of the HelloWorldView class. We can save some typing and generate the constructor by choosing Source > Generate Constructors from Superclass, as shown in Figure 4-18. Eclipse can also automatically suggest items from the Refactor menu if you press Ctrl+L when the cursor is on a section of code. For example, if you implement an interface on a class but have not yet written the methods that must be implemented, you can press Ctrl+L for the suggestions and Eclipse presents a command to automatically implement the required methods. Syntax may be all the compiler needs to understand code, but adding code syntax coloring in the editor makes it much easier for us to read the Java

152

Chapter 4

Software Engineering for Ajax

Figure 418. Automatically creating a class constructor

code, as illustrated in Figure 4-19. The default syntax coloring in Eclipse uses a bold purple font for Java keywords like class, super, extends, and public, a green font for all comments, a blue font for fields, and a blue italic font for static fields. Now lets create a HorizontalPanel in the constructor and add a couple widgets to it. As you type, Eclipse watches for errors. After you type the word HorizontalPanel it will appear as an error, because the class has not been imported. Use the same technique as before to import it (Ctrl+Shift+M or Source > Add Import). When you start typing to call a method on the panel, Eclipses content assist feature displays a list of method suggestions, as shown in Figure 4-20.

Figure 419. An automatically generated constructor

Writing Java Code in Eclipse

153

Figure 420. Content assist in Eclipse

Eclipse automatically shows the suggestions, or you can force them to display by pressing Ctrl+Spacebar. In this case we want the add method, but we can also get an idea of the other methods available. In a way, content assist not only helps speed up typing and locating method names, but it also acts as an educational tool for the class youre using. Instead of leafing through documentation, you can pick up quite a bit of information about a library through this feature. Another way to educate yourself about a class youre using is to use the editors Ctrl+Click feature, shown in Figure 4-21. Using Ctrl+Click on a variable, class, or method in the editor takes you to its source in the Eclipse editor. For example, if you click on a variable name, the editor takes you to the variable declaration. If you click on a class name, it takes you to the class Java file, and if you click on a method, it takes you to the method declaration. This allows you to browse your source code with the same convenience and efficiency as browsing the web. This even works with classes in the GWT library, since the GWT jar file contains the Java source code. When you cant find what youre looking for while browsing your code, Eclipse provides rich support for searching. First of all, there is a simple single file Find/Replace command which you can access from the Edit menu or by pressing Ctrl+F. This is a standard find and replace feature that you find in most editors. On top of this single file find, Eclipse provides a rich multifile search feature that you can access from the Search menu or by pressing Ctrl+H. Figure 4-22 shows the Search dialog.

154

Chapter 4

Software Engineering for Ajax

Figure 421. Using Ctrl+Click to browse source code

Figure 422. Searching in Eclipse

The first tab in the Search dialog, File Search, lets you search for any string within any files in your workspace. The second tab, Java Search, provides a more restrictive search since it has an understanding of the Java language. In this tab you can search for specific instances of a certain string. For example, the dialog in Figure 4-22 shows searching for toString when its being called as a reference. This search would ignore any other occurrence of toString, such as toString declarations or any comments. The file search also allows you to replace matching values across files. This is helpful for refactoring code. For example, you could replace all occurrences of HelloWorld in our project files with MyFirstApp. Eclipse provides refactoring support beyond multiple file search and replace. For example, you can change the name of the HelloWorld class

Writing Java Code in Eclipse

155

Figure 423. Renaming a class

to MyFirstApp with the Refactor > Rename command, as shown in Figure 4-23. When you make changes through the Refactor menu, Eclipse ensures that references using the original value are also changed. This method is less error prone than doing a search and replace. Eclipse has many more time saving refactoring commands, and you can easily find them by checking the Refactor context menu for any item, including highlighted code. Eclipse also has many more features that can help you write your code. Even though they may not seem like dramatic productivity features, as you start using more of them youll find yourself writing code faster and with less frustrations. Writing code is only one piece of the application development puzzle that Eclipse enhances. The next piece well look at is its debugging support.

156

Chapter 4

Software Engineering for Ajax

Debugging in Eclipse
Eclipse provides a nice environment for debugging a running Java application. When you run a GWT application in hosted mode, Eclipse runs it as a Java application and you can debug it within Eclipse. This ability to debug a browser-based web application is a huge advancement for the Ajax development process. Earlier in this chapter you saw that an Eclipse launch configuration can be automatically created by the GWT applicationCreator script by using the eclipse option when creating the application. You can launch the application in hosted mode from Eclipse using either the Run or Debug command. When launched, the application runs in the hosted mode browser. In Debug mode, the hosted mode browser is connected to Eclipse and can use Eclipses debugging commands. First, lets look at breakpoints. Breakpoints allow you to set a location within your code where, when reached, the application running would break and pass control to the debugger. This lets you inspect variables or have the application step through the code line by line to analyze the program flow. To see how this works, add a breakpoint to the HelloWorld application on the first line of the buttons ClickListener.onClick method by right-clicking on the left margin of that line in the editor and selecting Toggle Breakpoint, as shown in Figure 4-24. Youll see the breakpoint added represented by a blue circle in the margin. Alternatively, you can double-click the same spot in the margin to toggle the breakpoint. Now when you debug the application, Eclipse will break into the debugger when it reaches the breakpoint. In this case it will happen when you click on the button. Start the debugger by opening the Debug menu from the Bug icon on the toolbar and selecting HelloWorld, as shown in Figure 4-25. When the HelloWorld application opens in the hosted mode browser, click on its Click Me button to see Eclipse display the debugger. You should see Eclipse in the Debug perspective, as shown in Figure 4-26. This is the view you should become familiar with if you are going to be building an Ajax application of any decent size. It provides you with a working view of exactly what is going on in your application. If your appli-

Debugging in Eclipse

157

Figure 424. Setting breakpoints

Figure 425. Starting the debugger

cation exhibits strange behavior, you can set a breakpoint to see exactly what is happening. If you are a JavaScript developer, this type of debugging tool may be new to you and seem somewhat complex. However, it is definitely worth the effort to learn how to use it properly, since it will save you a lot of time when finding bugs. Instead of printing out and analyzing logs, you can set a breakpoint and step through the program one line at a time, while checking variable values, to determine what the bug is. Lets briefly look at some of the tools in the Debug perspective. First of all, there are the controls that sit above the stack. The Resume and Terminate buttons are the green triangle and red square, respectively. Resume lets the program continue running. In Figure 4-26 it is stopped on the breakpoint. The Terminate button ends the debug session. You typically end your program by closing the hosted mode browser windows; however,

158

Chapter 4

Software Engineering for Ajax

Debug controls

Application stack

Variable browser

Current line

Figure 426. The debugging perspective in Eclipse

when you are in a breakpoint, the application has stopped and you cannot access the interface of the hosted mode browser. The only way to end the program in this case is to use the Terminate button. The yellow arrows next to the Resume and Terminate buttons are used for stepping through the application. Taking a step when the application has stopped on a breakpoint executes one step. This allows you to see how one step of code affects any variables. It also lets you inch your way through the program and at a slow pace see how it flows. The first step button, Step Into, takes a step by calling the next method on the current line. Typically this will take you to another method and add a line to the stack. You would use this button when you want to follow the program flow into a method. To avoid stepping into another method, use the next step button, Step Over, which executes the current line, calls any methods, and stops on the next line in the current method. The third yellow arrow button, Step Return, executes the rest of the current method and returns to the calling method, where it stops.

Debugging in Eclipse

159

Underneath the debug controls is the calling stack.2 This is actually a tree that lists threads in the Java application with their stacks as children. The stacks are only visible if the thread is stopped on a breakpoint. Ajax applications are single threaded, so we only need to worry about the one thread and its stack. When we hit the breakpoint in the onClick method, the single JavaScript thread displays its method call stack with the current method highlighted. You will find the stack particularly helpful to see when and how a method is called. You can click on other methods in the stack to look at their code in the editor. When you browse the stack like this, the Debug perspective adjusts to the currently selected line on the stack. For example, the editor will show the line in the selected method where the child method was called. It will also adjust the Variables view to show the variables relevant to the currently selected method. The Variables view lists local and used variables in the current method. The list is a columned tree that lets you browse each variables contents, and if it is an object, displays its value in the second column. An area on the bottom of the view displays text for the currently selected variable using its toString method. Sometimes stepping through an application with breakpoints isnt enough to find and fix problems. For example, an exception may occur at an unknown time, and placing a breakpoint would cause the debugger to break perhaps thousands of times before you encountered the exception. This is obviously not ideal. Fortunately, Eclipse provides a way to break into the debugger when a specific exception occurs. To add an exception breakpoint you simply need to choose Run > Add Java Exception Breakpoint. This displays the dialog shown in Figure 4-27. In this dialog you select the exception youd like to break on. The list is a dynamically updating list filtered by the text entered. Figure 4-27 shows breaking on Javas ArrayIndexOutOfBoundsException. After clicking on OK, you can see that the breakpoint was added by looking at the Breakpoints view in the Debug perspective shown in Figure 4-28

2. A calling stack is a list of methods calls in an application, where each item on the stack is a method preceded by its calling method. So, for example, when a method completes, control returns to the calling method on the top of the stack.

160

Chapter 4

Software Engineering for Ajax

Figure 427. Adding an exception breakpoint

Figure 428. The list of breakpoints in Eclipse

To test this, lets write some code that will cause an index to be out of bounds:
public void onModuleLoad() { int[] ints = new int[1000]; for( int i = 0; i<=1000; i++ ){ ints[i] = i; }

Now when running the application in Debug mode, Eclipse breaks when this code tries to write to the 1,001st int in the array (if you bump into another out-of-bounds exception when trying this, press the Resume button). Figure 4-29 shows the Debug perspective stopping on the exception breakpoint.

Debugging in Eclipse

161

Figure 429. Breaking into the debugger on an exception

Notice that the current line is the line where the out of bounds exception occurs. The value of i can be seen in the variables window as 1000 (arrays start at 0, so index 1,000 is the 1,001st item and over the bounds which was set at 1,000 items). The benefit of this type of breakpoint is that we did not need to step through 1,000 iterations of the loop to see where the problem is. Of course this is a trivial example, but you can apply this technique to more complex examples that exhibit similar behavior. Now that we know we have a bug in our HelloWorld code, we can use another great feature of Eclipse that allows us to update the code live and resume the application without restarting. With the application stopped at the exception breakpoint, lets fix the code so that it looks like Figure 4-30. Weve set the comparison operation to less than instead of less than or equals, and removed the 1,000 value to use the length property of the array. Save the file, resume the application, and then click the Refresh button on the hosted mode browser. Youll see that the application runs the

162

Chapter 4

Software Engineering for Ajax

Changed <=1000 to < ints.length

Figure 430. Fixing the code while debugging

new fixed code and does not encounter the exception. This technique saves quite a bit of time which would otherwise be spent restarting the hosted mode browser. Also, reducing breaks in your workflow helps keep your mind on the task at hand.

Organizing Your Application Structure


When you generate an application using GWTs applicationCreator script, the script creates files and directories that follow a recommended structure. Each application that you create shares your Projects directory. Figure 4-31 shows how the directory looks for the HelloWorld generated application. Figure 4-32 shows the directory result after running the applicationCreator again and adding the new application, HelloWorld2, to the same Eclipse project used for HelloWorld. Notice that new scripts were created for the HelloWorld2 application. The applicationCreator script creates the application source files in the src directory, and shares this directory with the first HelloWorld application as shown in Figure 4-33. The source code is organized in standard Java package structure. Since we created the application as com.gwt.examples.HelloWorld2, the script generates the source files in the src/com/gwt/examples directory. This directory structure technique is a nice way of organizing Java modules and applications. It allows you to add packages and give them a unique location in the source tree, avoiding overwriting other classes that may be in a different package but have the same name. It also gives you a unique way to refer to a class from Java code.

Organizing Your Application Structure

163

Figure 431. Directory structure for the HelloWorld application

Figure 432. Directory structure after adding a new application

Figure 433. Two applications sharing the same source directory

Each generated GWT application has a module file and other source files in the client subdirectory and public subdirectory. Figure 4-33 shows the module file for HelloWorld2, HelloWorld2.gwt.xml. This file specifies the applications configuration options for the GWT compiler. The generated module file looks like this:
<module> <!-- Inherit the core Web Toolkit stuff. <inherits name='com.google.gwt.user.User'/>

-->

164

Chapter 4

Software Engineering for Ajax

<!-- Specify the app entry point class. --> <entry-point class='com.gwtapps.examples.client.HelloWorld2'/> </module>

This is the minimum specification that the application needs to run. The GWT compiler needs to know the class that acts as the entry point to the application, specified with the entry-point tag, and it needs to use the com.google.gwt.user.User module for its user interface. When you need to use other modules in your application you specify their location here. The module file has many more configuration options, all of which are outlined on the GWT web site at http://code.google.com/webtoolkit. Now lets look inside the public folder shown in Figure 4-34. For each generated application, the script creates a new HTML host file in the public directory. The GWT compiler considers files placed in the public directory to be part of the distribution. In other words, when you compile your application, GWT will copy all of the files in this directory to the www output directory. For example, we could move the CSS from inside the HTML host file to a separate CSS file and place it in this directory. Other common files you might place in this directory are images that used in the applications user interface.

Figure 434. The public folder holding the static application files

The generated Java source file for the applications is found in the client directory, as shown in Figure 4-35. When the GWT compiler compiles the Java source to JavaScript, it compiles the Java files in this directory. Any files outside of this directory will not be compiled to JavaScript, and if you use them you will get an exception when compiling or running in hosted mode. However, using the inherits tag in your module file tells the GWT compiler to use another module.

Figure 435. The client directory holding the files that will be compiled to JavaScript

Organizing Your Application Structure

165

The GWT compile automatically includes subdirectories and packages in the client directory without inheriting a module. This is useful for organizing subcategories of code within your application. For example, many of the sample applications in this book use a model-view-controller (MVC) architecture and keep the model and view in subpackages. Figure 4-36 shows this type of organization for Chapter 7s Multi-Search sample application. You can use this to organize your client-side code into categories other than model and view.

Figure 436. MVC organization inside the client directory

There may be situations where youll have application code that shouldnt be compiled to JavaScript and shouldnt be in the client directory; for example, when writing server-side code in Java, perhaps using GWTs RPC servlet. The common place to put this server-side code is in a server directory. For example, in the Instant Messenger application in Chapter 9 places the servlet class in the server subdirectory, as shown in Figure 4-37. Since this is outside of the client directory, the GWT compile ignores the code when compiling the client. Typically the GWT compiler will not be able to compile server-side code since it usually uses packages that arent emulated by GWT and would not be useful in a browser.

Figure 437. Server-side code is placed outside the client directory

The reverse is possible, however. The server classes can use classes in the client directory as long as they dont rely on browser features. The Instant Messenger application does this to share the Java classes that are used to transmit data over RPC between the client and the server.

166

Chapter 4

Software Engineering for Ajax

Finally, when youre ready to deploy your application, you run the generated compile script. GWT copies all of the files used for distribution, including the generated JavaScript files and all of the files in the public directory, to the applications directory inside the www directory. The compiler names the applications directory with the full module name, as shown in Figure 4-38.

Figure 438. The GWT writes the compiled and static files to the www directory

Testing Applications
Having the capability to build Ajax applications with Java gives you many tools that let you maintain larger applications with less work. One very important aspect of maintaining a large application is being able to easily create unit tests for most, if not all, functionality. This need comes from a common problem with software development: the code size grows to a point where small changes can have cascading effects that create bugs. It has become common practice to incorporate heavy testing into the development cycle. In the traditional waterfall development cycle you would write code to a specification until the specification was complete. Then the application would be passed to testers who would look for bugs. Developers would respond to bug reports by fixing the bugs. Once all the bugs were fixed, the product would be shipped. Figure 4-39 illustrates the steps in traditional software development testing. The problem encountered with this type of development cycle is that during the bug finding and fixing phase, code changes can easily cause more

Testing Applications

167

More features No more features

More bugs

No more bugs

Add feature

Find bugs/change code

Figure 439. Old-style testing = bad

bugs. To fix this problem, testers would need to start testing right from the beginning after every code change to ensure new bugs werent created and old bugs didnt reappear. One successful testing methodology has developers write automated unit tests before they write the features. The tests cover every use case of the new feature to be added. The first time the test is run, it will fail for each case. The development process then continues until each test case in the unit test is successful. Then the unit test becomes part of a test suite for the application and is run before committing any source code changes to the source tree. If a new feature causes any part of the application to break, others test in the automated test suite will identify this problem, since every feature of the application has had tests built. If a bug is found at this point, it is relatively easy to pinpoint the source since only one new feature was added. Finding and fixing bugs early in the development lifecycle like this is much easier and quicker than finding and fixing them at the end. The test suite grows with the application. The initial investment in time to produce the unit tests pays off over the long run since they are run again on every code change, ensuring each features health. Figure 4-40 illustrates this process. In practice, when comparing this approach to the one illustrated in Figure 4-39, there is a large time saving from finding bugs earlier and less of a need for a large testing team since the developer is responsible for much of the testing.
More features

No more bugs

No more features

Add feature test

Add feature

Run all tests

More bugs

Change code

Figure 440. Test-first testing = good

168

Chapter 4

Software Engineering for Ajax

This technique is relatively novel for client-side web applications. Testing is reduced to usability testing and making sure that different browsers render pages properly with traditional web applications. This is one of the great things about HTML. Its a declarative that leaves little room for logical bugs. Its easy to deploy HTML web pages that work (browser-rendering quirks aside). However, using JavaScript introduces the possibility of logic bugs. This wasnt too much of a problem when JavaScript was being used lightly, but for Ajax applications heavily using JavaScript, logical bugs are somewhat of a problem. Since JavaScript is not typed and does not have a compile step, many bugs can only be found by running the application, which makes the creation of unit tests difficult. Furthermore, it is difficult to test an entire application through its interface. Many simple bugs, such as trying to call an undefined function, cannot be caught without running the program and trying to execute the code that has the bug, but by using Java you could catch these bugs immediately in the IDE or at compile time. From a testing perspective, it does not make sense to build large Ajax applications with JavaScript.

Using JUnit
JUnit is another great Java tool that assists in creating an automated testing for your application. It provides classes that assist in building and organizing tests, such as assertions to test expected results, a test-case base class that allows you to set up several tests, and a mechanism to join tests together in a test suite. To create a test case for JUnit you would typically extend the TestCase class, but since GWT applications require a special environment, GWT provides a GWTTestCase class for you to extend. Lets walk through the creation of a test case for the Multi-Search application in Chapter 7. The first step is to use the GWT junitCreator script to generate a test case class and some scripts that can launch the test case. The junitCreator script takes several arguments to run. Table 4-1 outlines each argument. To run this script for the Multi-Search application we can use the following command:
junitCreator -junit E:\code\eclipse\plugins\org.junit_3.8.1\junit.jar -module com.gwtapps.multisearch.MultiSearch -eclipse GWTApps com.gwtapps.multisearch.client.MultiSearchTest

line ong

Table 41 junitCreator Script Arguments Example -junit E:\code\eclipse\plugins\org.junit_3.8.1\junit.jar

Argument

Description

junit

Lets you define the location of the junit jar file. You can find a copy in the plugin directory of your Eclipse installation.

module

Specifies the GWT module that youll be testing. It is required since the environment needs to run this module for your test. -eclipse GWTApps

-module com.gwtapps.multisearch.MultiSearch

eclipse

Specifies your Eclipse project name if you want to generate Eclipse launch configurations.

The last argument should be the class name for the test case. You would typically use the same package as the one being tested.

com.gwtapps.multisearch.client.MultiSearchTest

169

170

Chapter 4

Software Engineering for Ajax

Figure 441. Using junitCreator to generate a test case

Figure 4-41 shows the output from this command. The script created two scripts, two launch configurations for launching the test in web mode or hosted mode, and one test case class that is stored in the test directory. In Eclipse the test case class will look like Figure 4-42. The generated test case has two methods. The first, getModuleName, is required by GWT and must specify the module that is being tested. The junitCreator script has set this value to the Multi-Search module because it was specified with the module command line argument. The second method, a test case, is implemented as a simple test that just asserts that the value true is true. You can build as many test cases as you like in this one class.

Figure 442. A generated test case in Eclipse

Testing Applications

171

You can run the tests by running the scripts generated by junitCreator. Alternatively, you can launch JUnit inside Eclipse for a visual representation of the results. Running inside Eclipse also lets you debug the JUnit test case, which can greatly assist in finding bugs when a test case fails. Since junitCreator created a launch configuration for Eclipse, we can simply click the Run or Debug icons in the Eclipse toolbar and select the Multi SearchTest launch configuration from the drop-down menu. After launching this configuration, the JUnit view automatically displays in Eclipse. When the test has completed, you will see the results in the JUnit view, as shown in Figure 4-43. Notice the familiar check marks, which are displayed in green in Eclipse, next to the test case indicating that the test case was successful.

Figure 443. Running a JUnit test case from Eclipse

Now lets create a test case for each type of search engine that the application uses. Adding the following code to the test class creates four new tests:
protected MultiSearchView getView(){ MultiSearchView view = new MultiSearchView( new MultiSearchViewListener(){ public void onSearch( String query ){} }); RootPanel.get().add( view ); return view; } protected void doSearchTest( Searcher searcher ){ searcher.query( "gwt" ); }

172

Chapter 4

Software Engineering for Ajax

public void testYahoo() { doSearchTest( new YahooSearcher( view ) ); } public void testFlickr() { doSearchTest( new FlickrSearcher( view ) ); } public void testAmazon() { doSearchTest( new AmazonSearcher( view ) ); } public void testGoogleBase() { doSearchTest( new GoogleBaseSearcher( view ) ); }

The first two methods, getView and doSearchTest, are helper methods for each test in this test case. The getView method simply creates a view, the MultiSearchView defined in the application, and adds it to the RootPanel so that it is attached to the document. Then the doSearchTest method sends a query to a Searcher class implementation. Each test case instantiates a different Searcher implementation and sends it to the doSearchTest method. When JUnit runs, each test case runs and submits a query to the respective search engine. Figure 4-44 shows what the result looks like in the Eclipse JUnit view. If any search failed by an exception being thrown, then the stack trace for the exception would display in the right pane of this view and a red X icon would display over the test case. The problem with this test case is that it doesnt verify the results. JUnit provides many assertion helper methods that compare actual results to

Figure 444. Running several tests in one test case

Testing Applications

173

expected results. However, in this case our results are asynchronous; that is, they dont arrive until after the test case completes. GWT provides help with this since much of Ajax development is asynchronous with the delayTestFinish method. To use this method we need to have a way of validating an asynchronous request. When we have validated that an asynchronous request is complete, then we call the finishTest method. In the case of the MultiSearch test, we will validate when we receive one search result. To do this we need to hook into the application to intercept the asynchronous event. This requires a bit of knowledge about the application and may seem a little obscure otherwise. We will create a mock object, which is an object that pretends to be another object in the application, to simulate the SearchResultsView class. By simulating this class we will be able to extend it and override the method that receives search results. The class can be declared as an inner class on the test case like this:
private class MockSearchResultsView extends SearchResultsView { public MockSearchResultsView( SearchEngine engine ){ super(engine); } public void clearResults(){} public void addSearchResult( SearchEngineResult result ){ assertNotNull(result); finishTest(); } }

The class overrides the addSearchResult method, which one of the Searcher classes calls when a search result has been received from the server. Instead of adding the result to the view, this test case will use one of JUnits assert methods, assertNotNull, to assert that the search engine result object is not null. Then it calls the GWTs finishTest method to indicate that the asynchronous test is complete. To run this test we need to change the doSearchTest method on the test case to insert the mock view and tell JUnit to wait for an asynchronous response:
protected void doSearchTest( Searcher searcher ){ searcher.setView( new MockSearchResultsView(searcher.getView().getEngine()));

174

Chapter 4

Software Engineering for Ajax

searcher.query( "gwt" ); delayTestFinish(5000); }

In this code we set the view of the searcher to the mock view that weve created, and then call the delayTestFinish method with a value of 5,000 milliseconds (5 seconds). If the test does not complete within 5 seconds, it will fail. If the network connection is slow, you may want to consider a longer value here to properly test for errors. Running these tests at this point test the application code in the proper GWT environment and with asynchronous events occurring. You should use these testing methods as you build your application so you have a solid regression testing library.

Benchmarking
When using GWT to create Ajax applications, taking user experience into consideration almost always comes first. Part of creating a good user experience with an application is making it perform well. Fortunately, since GWT has a compile step, each new GWT version can create faster code, an advantage that you dont have with regular JavaScript development. However, you probably shouldnt always rely on the GWT team to improve performance and should aim at improving your code to perform better. Starting with release 1.4, GWT includes a benchmarking subsystem that assists in making smart performance-based decisions when developing Ajax applications. The benchmark subsystem works with JUnit. You can benchmark code through JUnit by using GWTs Benchmark test case class instead of GWTTestCase. Using this class causes the benchmarking subsystem to kick in and measure the length of each test. After the tests have completed, the benchmark system writes the results to disk as an XML file. You can open the XML file to read the results, but you can view them easier in the benchmarkViewer application that comes with GWT. Lets look at a simple example of benchmarking. We can create a benchmark test case by using the junitCreator script in the same way we would for a regular test case:
junitCreator -junit E:\code\eclipse\plugins\org.junit_3.8.1\junit.jar -module com.gwtapps.desktop.Desktop -eclipse GWTApps com.gwtapps.desktop.client. CookieStorageTest

Testing Applications

175

In this code were creating a test case for the cookie storage feature in Chapter 6s Gadget Desktop application. The application uses the Cookie Storage class to easily save large cookies while taking into account browser cookie limits. In this test were going to measure the cookie performance. First, we extend the Benchmark class instead of GWTTestCase:
public class CookieStorageTest extends Benchmark { public String getModuleName() { return "com.gwtapps.desktop.Desktop"; } public void testSimpleString(){ try { CookieStorage storage = new CookieStorage(); storage.setValue("test", "this is a test string"); assertEquals( storage.getValue("test"), "this is a test string" ); storage.save(); storage.load(); assertEquals( storage.getValue("test"), "this is a test string"); } catch (StorageException e) { fail(); } } }

You can run this benchmark from the Eclipse JUnit integration or the launch configuration generated by the junitCreator script. The test simply creates a cookie, saves it, loads it, and then verifies that it hasnt changed. The generated XML file will contain a measurement of the time it took to run this method. At this point the benchmark is not very interesting. We can add more complex benchmarking by testing with ranges. Using ranges in the benchmark subsystem gives you the capability to run a single test case multiple times with different parameter values. Each run will have its duration measured, which you can later compare in the benchmark report. The following code adds a range to the cookie test to test writing an increasing number of cookies:
public class CookieStorageTest extends Benchmark { final IntRange smallStringRange = new IntRange(1, 64, Operator.MULTIPLY, 2); public String getModuleName() { return "com.gwtapps.desktop.Desktop"; }

176

Chapter 4

Software Engineering for Ajax

/** * @gwt.benchmark.param cookies -limit = smallStringRange */ public void testSimpleString( Integer cookies ){ try { CookieStorage storage = new CookieStorage(); for( int i=0; i< cookies.intValue(); i++){ storage.setValue("test"+i, "this is a test string"+i); assertEquals( storage.getValue("test"+i), "this is a test string"+i ); } storage.save(); storage.load(); for( int i=0; i< cookies.intValue(); i++){ assertEquals( storage.getValue("test"+i), "this is a test string"+i ); } } catch (StorageException e) { fail(); } } public void testSimpleString(){ } }

This code creates an IntRange. The parameters in the IntRange constructor create a range that starts at one and doubles until it reaches the value 64 (1, 2, 4, 8, 16, 32, 64). GWT passes each value in the range into separate runs of the testSimpleString method. GWT knows to do this by the annotation before the method, which identifies the parameter and the range to apply. Notice that there is also a version of the testSimpleString method without any parameters. You need to provide a version of this method with no arguments to run in JUnit since it does not support tests without parameters. The benchmark subsystem is aware of this and is able to choose the correct method. After running this code we can launch the benchmarkViewer application from the command line in the directory that the reports were generated in (this defaults to the Projects directory):
benchmarkViewer

The benchmarkViewer application shows a list of reports that are in the current directory. You can load a report by clicking on it in the list. Each

Testing Applications

177

Figure 445. Benchmark results for the cookie test

report contains the source code for each test along with the results as a table and a graph. Figure 4-45 shows the result of the testSimpleString test. The benchmark system also recognizes beginning and ending methods. Using methods like these allows you to separate set up and take down code for each test that you dont want measured. For example, to define a setup method for the testSimpleString test, you would write the following code:
public void beginSimpleString( Integer cookies ){ /* do some initialization */ }

178

Chapter 4

Software Engineering for Ajax

Building and Sharing Modules


Each GWT module is not necessarily a full application, but it can be used as a reusable library for other applications instead. The GWT module structure, also used for applications, gives you the tools necessary to package your module and share it with other applications. In fact, GWT itself is divided into several modules, as youve seen with the user interface, XML, JSON, HTTP, and RPC modules, so youve already used the process of importing other libraries.

Using Modules
GWT modules are distributed as jar files that you can include in your application by adding them to your projects classpath and inheriting their project name in your applications module file. This is the same process that you use to include the GWT library classes in your application. In this case GWT automatically adds the module jar file, gwt-user.jar, to your projects classpath when you generate the project using the GWT createProject script. The createApplication script then generates a module XML file for your application and automatically adds the com.google.gwt.user.User module to it. When we generate the module XML file for the Gadget Desktop application in Chapter 6, we get the following XML:
<module> <inherits name='com.google.gwt.user.User'/> <entry-point class='com.gwtapps.desktop.client.Desktop'/> </module>

This module file tells the GWT compiler how to compile the application to JavaScript. The inherits element tells the compiler that we are using classes from the name module, which will also need to be compiled to JavaScript. We can continue to add modules from gwt-user.jar since the file is are already on the classpath. For new modules in other jar files, we first need to add the jar to the classpath. In Eclipse, you can do this by going to the projects Properties dialog and selecting the Libraries tab from Java Build Path, as shown in Figure 4-46. From here you can add and remove jar files. Notice that gwt-user.jar is already in the list. For the Gadget Desktop application we add the gwtgoogle-apis library to the project to use the Gears module from it. First,

Building and Sharing Modules

179

Figure 446. Editing the build path in Eclipse

we add the gwt-google-apis jar to this list, and then the applications module XML file inherits the Gears module like this:
<module> <inherits name='com.google.gwt.user.User'/> <inherits name='com.google.gwt.json.JSON'/> <inherits name='com.google.gwt.xml.XML'/> <inherits name='com.google.gwt.gears.Gears'/> <entry-point class='com.gwtapps.desktop.client.Desktop'/> </module>

Notice also that this project imports the JSON and XML modules which are already in the gwt-user.jar file. If you miss this stepadding the inherits tag to your applications module fileyou will get an error from the GWT compiler that it cant find the module that youre using.

Creating a Reusable Module


If youve built a GWT application, youve already built a reusable module. The only difference is that your application has specified an entry point and can be turned into a GWT application loaded on its own in the GWT

180

Chapter 4

Software Engineering for Ajax

hosted mode browser or web browser. You could reference the applications module file from another application to reuse its components. You create a module the same way you create an application, using GWTs applicationCreator script. You may want to use the ant flag with this script to build an ant file that will automatically package your module in a jar file for distribution. The module structure of GWT is hierarchical using inheritance. For example, if you write a module that inherits GWTs User module, then any module or application that uses your module also automatically inherits GWTs User module. This is an important feature, since it allows the users of your module to automatically get all the requirements to run. GWT takes this concept further and lets you also inject resources into modules to ensure CSS or other JavaScript libraries are automatically included. For example, if you were creating a module of widgets that required default CSS to be included, you could reference this in the module XML like this:
<module> <inherits name='com.google.gwt.user.User'/> <stylesheet src="widgets.css"/> </module>

The widgets file would need to be included in your modules public files, and when other modules inherit your module they would automatically get the widgets.css file without directly including it. You can similarly include JavaScript in your module using the script tag like this:
<module> <inherits name='com.google.gwt.user.User'/> <!-- Include google maps --> <script src="http://maps.google.com/ maps?file=api&amp;v=2&amp;key=ABQIAAAACeDba0As0X6mwbIbUYWv-RTbvLQlFZmc2N8bgWI8YDPp5FEVBQUnvmfInJbOoyS2v-qkssc36Z5MA"></script> </module>

This tag is similar to the script tag that you would use in your HTML file to include a JavaScript library, except that this file would be automatically included with every module that includes this module.

Deploying Applications

181

As of GWT 1.4 you can use image bundles to include resources with your reusable modules. Image bundles allow you to package several images together into a single image for deployment. If you use an image bundle within your module, applications that use your module will automatically generate the single image. In Chapter 6, images bundles are used to build the Gadget toolbar in the Gadget Desktop application.

Sharing a Compiled Application (Mashups)


Sometimes youd like to share your compiled JavaScript application for use on other web sites. As of GWT 1.4, other web sites can easily load your application using the cross-site version of the generated JavaScript. The cross-site version has xs appended to the package name for the JavaScript file name, and you can find it in the www directory after compiling an application. For example, to include the Hangman application developed in Chapter 1, you would use the following script tag:
<script language='javascript' src='http://gwtapps.com/hangman/ com.gwtapps.tutorial.Hangman-xs.nocache.js'></script>

Notice that this line differs from the line found in the original host HTML page for the application; it has the addition of xs in the filename and is loading the script from the gwtapps.com domain. Each application that you share may have additional requirements for integration on another site. In the Hangman example, the application looks for an HTML element with the ID hangman. so anyone including this on their site would need to also have the following HTML in the location where theyd like the Hangman application to show up:
<div id="hangman"></div>

Deploying Applications
Deploying a GWT application can be as easy as deploying a regular web page. A simple GWT client is made up of HTML and JavaScript files that can be copied to a directory on a web server and loaded into a browser. For example, the Gadget Desktop application in Chapter 6 does not use any server-side code, so its files for deployment are simply its JavaScript files,

182

Chapter 4

Software Engineering for Ajax

several image files, and the host HTML file. You can install this application on any web server simply by copying the files.

Deploying to a Web Server


Youve seen how to set up development environments with Java tools, run the GWT scripts, and use the GWT jar files, but for a client-side application these files are left on the development machine. You simply need to run the GWT compile script, or click the Compile button in the GWT hosted mode browser, to generate the files needed for deployment. For example, compiling the Gadget Desktop application can be done from the command line. Or it can be compiled from the hosted mode browser, as shown in Figure 4-47. GWT places these files in a directory named after your application inside the www directory for your project, as you can see in Figure 4-48. This is the file list that you would copy to a directory on your web server.

Figure 447. Compiling your application from the GWT hosted mode browser.

Deploying a Servlet to a Servlet Container


If you are using GWT-RPC, you will need to deploy your service implementation to a servlet container. Although the GWT hosted mode browser runs

Deploying Applications

183

Figure 448. The GWT compiler places the files to deploy in www

an embedded version of Tomcat, deploying to a regular Tomcat instance is somewhat different. If you are deploying to Tomcat, youll need to add your application to its webapps directory. Figure 4-49 outlines the steps to add your application to Tomcats directory structure.

184

Chapter 4

Software Engineering for Ajax

1. Tomcat installation

2. Your application 4. Your class files go here 5. GWT library goes here 3. Configure the servlet here

Figure 449. Steps to deploy your application to Tomcat

Lets look at the five steps shown in Figure 4-49. First you need to locate the installation directory for Tomcat. Second, you need to create your application directory under the webapps directory. Third, you need to set up your web.xml file in the WEB-INF directory for your application. For the Instant Messenger application, the file looks like this:
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>messenger</servlet-name> <servlet-class>com.gwtapps.messenger.server.MessengerServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>messenger</servlet-name> <url-pattern>/messenger</url-pattern> </servlet-mapping> </web-app>

Fourth, copy your servlet class to the class directory in the WEB-INF directory. Finally, fifth, copy the gwt-servlet.jar file to the lib directory in the WEB-INF directory. The gwt-servlet.jar file has the GWT classes required to support the server-side RPC. You could use gwt-user.jar instead, but gwt-servlet.jar is smaller and therefore preferred. Deployment can be automated by using a build tool such as Ant.

Deploying Applications

185

Automating Deployment with Ant


As you can see from the previous section, deployment to a server container often involves many steps of compiling code, copying files, and creating directories. When a task involves many steps like this, it is best to automate the process. Ant is the ideal Java tool for automating build tasks like this. With it you can accomplish all of the previous steps of deploying a GWT web application with one Ant step. Ant is a command line tool that accepts an XML build file. The build file contains a list of build targets with steps to accomplish build tasks. There is rich support for different types of steps, including copying files, creating directories, and compiling code. The Ant system is also extensible, so you can develop new steps or add new steps from other developers. Lets run through an example of how to build a GWT application for use on a servlet container with Ant. First, verify that you have Ant installed and in your path. You should be able to type ant version at the command line, as shown in Figure 4-50.

Figure 450. Verifying Ant is on your system

If you dont have Ant installed, you can download it from http:// ant.apache.org. After ensuring that Ant is installed on your development machine, you can write a build.xml file for a project. The following is the build.xml file we will use:
<project default="deploy"> <property name="gwtpath" value="/Users/ryan/lib/gwt-mac-1.4.10"/> <property name="gwtapipath" value="/Users/ryan/lib/gwt-google-apis-1.0.0"/> <property name="targetdir" value="${basedir}/www/${app}"/>

186

Chapter 4

Software Engineering for Ajax

<property name="wwwdir" value="${basedir}/www"/> <property name="srcdir" value="${basedir}/src"/> <property name="bindir" value="${basedir}/bin"/> <path id="classpath"> <pathelement location="${gwtapipath}/gwt-google-apis.jar"/> <pathelement location="${gwtpath}/gwt-user.jar"/> <pathelement location="${gwtpath}/gwt-dev-mac.jar"/> <pathelement location="${srcdir}"/> <pathelement location="${bindir}"/> </path> <target name="compile-gwt"> <java classname="com.google.gwt.dev.GWTCompiler" fork="true"> <classpath refid="classpath"/> <jvmarg value="-XstartOnFirstThread"/> <arg value="-out"/> <arg value="${wwwdir}"/> <arg value="${app}"/> </java> </target> <target name="compile" depends="compile-gwt"> <mkdir dir="${targetdir}/WEB-INF/classes"/> <javac srcdir="${srcdir}" destdir="${targetdir}/WEB-INF/classes" excludes="**/client/*.java"> <classpath refid="classpath"/> </javac> </target> <target name="deploy" depends="compile"> <mkdir dir="${targetdir}/WEB-INF/lib"/> <copy todir="${targetdir}/WEB-INF/lib" file="${gwtpath}/gwt-servlet.jar"/> <copy tofile="${targetdir}/WEB-INF/web.xml" file="${basedir}/ ${app}.web.xml"/> </target> </project>

The file begins by defining a project element with a default target. This target is run when one is not specified on the command line. The first few elements inside the project tag are property definition elements. You can place variables in these elements that will be reused throughout the build file. For example, in this file we have the source directories and jar directories set for use later. Inside the attributes you can see how the properties can be referenced with the ${name} format. Before the targets are defined in the file, we set a path element. This element lists the jar files

Deploying Applications

187

and directories that are on the classpath. We use this classpath later and can refer to it by its ID. The first target, compile-gwt, runs the GWT compiler on our GWT module. The module is not specified in this target. Instead the ${app} placeholder is used. We have not defined this as a property, but we can pass in this variable as a command line argument. This gives the build file the flexibility of being used for more than one application. Running this target generates the compiled JavaScript files for the application and copies all of the public files used for the project to the www directory. The second target, compile, uses the regular javac compiler to compile all of the other Java class files. These are class files that will be needed on the server and will include the GWT-RPC service servlet if one is used. The Ant script copies these class files to the www directory under WEB-INF/ classes. This is the standard location for class files for a servlet container web application. The final target, deploy, copies the required GWT library, gwt-servlet.jar, to the WEB-INF/lib directory. This is the standard location for jar files for a servlet container web application. The target also copies a predefined web.xml file to the www directory. The web.xml file is required to describe the servlets in the web application. Running the task for the Instant Messenger application in Chapter 9 results in the output shown in Figure 4-51. Once this is complete, we should have a www directory that is ready to be used in a servlet container, and which follows the conventions for servlet containers for file names and locations, as illustrated in Figure 4-52.

Figure 451. Compiling and deploying with Ant

188

Chapter 4

Software Engineering for Ajax

Figure 452. The output from an Ant script

Summary
GWT simplifies real software engineering for Ajax applications. This was really lacking when attempting to build substantial applications based on JavaScript. Using Eclipse to write and debug applications can substantially increase development productivity. Java organization and modularization helps you decouple application parts and leverage existing code. Testing and benchmarking using JUnit helps ensure that your applications are of high quality and perform well. When its time to deploy your application, Ant can automate any tedious tasks. Overall, the ability to leverage the vast range of mature Java software engineering tools is a significant part of creating great Ajax applications with GWT.

I S B N : 0 -321-32193 - 6

B U Y TH E b OO K TO DAY

Scripting in Java
Languages, Frameworks, and Patterns

Dejan Bosanac

Upper Saddle River, NJ Boston Indianapolis San Francisco New York Toronto Montreal London Munich Paris Madrid Cape Town Sydney Tokyo Singapore Mexico City

CHAPTER 1

I NTR ODUCTION S CRIPTING


T

TO

he main topic of this book is the synergy of scripting technologies and the Java platform. I describe projects Java developers can use to create a more powerful development environment, and some of the practices that make scripting useful. Before I start to discuss the application of scripting in the Java world, I summarize some of the theory behind scripting in general and its use in information technology infrastructure. This is the topic of the first two chapters of the book, and it gives us a better perspective of scripting technology as well as how this technology can be useful within the Java platform.

To begin, we must define what scripting languages are and describe their characteristics. Their characteristics greatly determine the roles in which they could (should) be used. In this chapter, I explain what the term scripting language means and discuss their basic characteristics. At the end of this chapter, I discuss the differences between scripting and system-programming languages and how these differences make them suitable for certain roles in development.

SCRIPTING

IN JAVA

Background
The definition of a scripting language is fuzzy and sometimes inconsistent with how scripting languages are used in the real world, so it is a good idea to summarize some of the basic concepts about programming and computing in general. This summary provides a foundation necessary to define scripting languages and discuss their characteristics. Lets start from the beginning. Processors execute machine instructions, which operate on data either in the processors registers or in external memory. Put simply, a machine instruction is made up of a sequence of binary digits (0s and 1s) and is specific to the particular processor on which it runs. Machine instructions consist of the operation code telling the processor what operation it should perform, and operands representing the data on which the operation should be performed. For example, consider the simple operation of adding a value contained in one register to the value contained in another. Now lets imagine a simple processor with an 8-bit instruction set, where the first 5 bits represent the operation code (say, 00111 for register value addition), and the registers are addressed by a 3-bit pattern. We can write this simple example as follows:
00111 001 010

In this example, I used 001 and 010 to address registers number one and two (R1 and R2, respectively) of the processor. This basic method of computing has been well known for decades, and Im sure you are familiar with it. Various kinds of processors have different strategies regarding how their instruction sets should look (RISC or CISC architecture), but from the software developers point of view, the only important fact is the processor is capable of executing only binary instructions. No matter what programming language is used, the resulting application is a sequence of machine instructions executed by the processor.

CHAPTER 1

What has been changing over time is how people create the order in which the machine instructions are executed. This ordered sequence of machine instructions is called a computer program. As hardware is becoming more affordable and more powerful, users expectations rise. The whole purpose of software development as a science discipline is to provide mechanisms enabling developers to craft more complex applications with the same (or even less) effort as before. A specific processors instruction set is called its machine language. Machine languages are classified as first-generation programming languages. Programs written in this way are usually very fast because they are optimized for the particular processors architecture. But despite this benefit, it is hard (if not impossible) for humans to write large and secure applications in machine languages because humans are not good at dealing with large sequences of 0s and 1s. In an attempt to solve this problem, developers began creating symbols for certain binary patterns, and with this, assembly languages were introduced. Assembly languages are secondgeneration programming languages. The instructions in assembly languages are just one level above machine instructions, in that they replace binary digits with easy-to-remember keywords such as ADD, SUB, and so on. As such, you can rewrite the preceding simple instruction example in assembly language as follows:
ADD R1, R2

In this example, the ADD keyword represents the operation code of the instruction, and R1 and R2 define the registers involved in the operation. Even if you observe just this simple example, it is obvious assembly languages made programs easier for humans to read and thus enabled creation of more complex applications. Although they are much more human-oriented, however, second-generation languages do not extend processor capabilities by any means.

SCRIPTING

IN JAVA

Enter high-level languages, which allow developers to express themselves in higher-level, semantic forms. As you might have guessed, these languages are referred to as thirdgeneration programming languages. High-level languages provide various powerful loops, data structures, objects, and so on, making it much easier to craft many applications with them. Over time, a diverse array of high-level programming languages were introduced, and their characteristics varied a great deal. Some of these characteristics categorize programming languages as scripting (or dynamic) languages, as we see in the coming sections. Also, there is a difference in how programming languages are executed on the host machine. Usually, compilers translate high-level language constructs into machine instructions that reside in memory. Although programs written in this way initially were slightly less efficient than programs written in assembly language because of early compilers inability to use system resources efficiently, as time passed compilers and machines improved, making system-programming languages superior to assembly languages. Eventually, high-level languages became popular in a wide range of development areas, from business applications and games to communications software and operating system implementations. But there is another way to transform high-level semantic constructs into machine instructions, and that is to interpret them as they are executed. This way, your applications reside in scripts, in their original form, and the constructs are transformed at runtime by a program called an interpreter. Basically, you are executing the interpreter that reads statements of your application and then executes them. Called scripting or dynamic languages, such languages offer an even higher level of abstraction than that offered by system-programming languages, and we discuss them in detail later in this chapter. Languages with these characteristics are a natural fit for certain tasks, such as process automation, system administration, and gluing existing software components together; in short, anywhere the strict syntax and constraints introduced by system-programming languages were getting in the way

CHAPTER 1

between developers and their jobs. A description of the usual roles of scripting languages is a focus of Chapter 2, Appropriate Applications for Scripting Languages. But what does all this have to do with you as a Java developer? To answer this question, lets first briefly summarize the history of the Java platform. As platforms became more diverse, it became increasingly difficult for developers to write software that can run on the majority of available systems. This is when Sun Microsystems developed Java, which offers write once, run anywhere simplicity. The main idea behind the Java platform was to implement a virtual processor as a software component, called a virtual machine. When we have such a virtual machine, we can write and compile the code for that processor, instead of the specific hardware platform or operating system. The output of this compilation process is called bytecode, and it practically represents the machine code of the targeted virtual machine. When the application is executed, the virtual machine is started, and the bytecode is interpreted. It is obvious an application developed in this way can run on any platform with an appropriate virtual machine installed. This approach to software development found many interesting uses. The main motivation for the invention of the Java platform was to create an environment for the development of easy, portable, network-aware client software. But mostly due to performance penalties introduced by the virtual machine, Java is now best suited in the area of server software development. It is clear as personal computers increase in speed, more desktop applications are being written in Java. This trend only continues. One of the basic requirements of a scripting language is to have an interpreter or some kind of virtual machine. The Java platform comes with the Java Virtual Machine (JVM), which enables it to be a host to various scripting languages. There is a growing interest in this area today in the Java community. Few projects exist that are trying to provide Java developers with the same power developers of traditional scripting languages have. Also, there is a way to execute your existing application written in a dynamic language such as Python inside the JVM and integrate it with another Java application or module.

SCRIPTING

IN JAVA

This is what we discuss in this book. We take a scripting approach to programming, while discussing all the strengths and weaknesses of this approach, how to best use scripts in an application architecture, and what tools are available today inside the JVM.

Definition of a Scripting Language


There are many definitions of the term scripting language, and every definition you can find does not fully match some of the languages known to be representatives of scripting languages. Some people categorize languages by their purpose and others by their features and the concepts they introduce. In this chapter, we discuss all the characteristics defining a scripting language. In Chapter 2, we categorize scripting languages based on their role in the development process.

Compilers Versus Interpreters


Strictly speaking, an interpreter is a computer program that executes other high-level programs line by line. Languages executed only by interpreters are called interpreted languages. To better understand the differences between compilers and interpreters, lets take a brief look at compiler architecture (see Figure 1.1). As you can see in Figure 1.1, translating source code to machine code involves several steps: 1. First, the source code (which is in textual form) is read character by character. The scanner groups individual characters into valid language constructs (such as variables, reserved words, and so on), called tokens. 2. The tokens are passed to the parser, which checks that the correct language syntax is being used in the program. In this step, the program is converted to its parse tree representation. 3. Semantic analysis performs type checking. Type checking validates that all variables, functions, and so on, in

CHAPTER 1

the source program have been used consistently with their definitions. The result of this phase is intermediate representation (IR) code. 4. Next, the optimizer (optionally) tries to make equivalent but improved IR code. 5. In the final step, the code generator creates target machine code from the optimized IR code. The generated machine code is written as an object file.
Tokens Scanner (Lexical analyzer) Parser (Syntax analyzer) Parse tree Semantical analyzer

Intermediate representation

Symbol table

Optimizer

Intermediate representation

Code generator

Target machine code

FIGURE 1.1

Compiler architecture

To create one executable file, a linking phase is necessary. The linker takes several object files and libraries, resolves all external references, and creates one executable object file. When such a compiled program is executed, it has complete control of its execution. Unlike compilers, interpreters handle programs as data that can be manipulated in any suitable way (see Figure 1.2).

10

SCRIPTING

IN JAVA

Interpreter

Output

Source code

Data

FIGURE 1.2

Interpreter architecture

As you can see in Figure 1.2, the interpreter, not the user program, controls program execution. Thus, we can say the user program is passive in this case. So, to run an interpreted program on a host, both the source code and a suitable interpreter must be available. The presence of the program source (script) is the reason why some developers associate interpreted languages with scripting languages. In the same manner, compiled languages are usually associated with system-programming languages. Interpreters usually support two modes of operation. In the first mode, the script file (with the source code) is passed to the interpreter. This is the most common way of distributing scripted programs. In the second, the interpreter is run in interactive mode. This mode enables the developer to enter program statements line by line, seeing the result of the execution after every statement. Source code is not saved to the file. This mode is important for initial system debugging, as we see later in the book. In the following sections, I provide more details on the strengths and weaknesses of using compilers and interpreters. For now, here are some clear drawbacks of both approaches important for our further discussion:
I

It is obvious compiled programs usually run faster than interpreted ones. This is because with compiled programs, no high-level code analysis is being done during runtime.

CHAPTER 1

11

An interpreter enables the modification of a user program as it runs, which enables interactive debugging capability. In general, interpreted programs are much easier to debug because most interpreters point directly to errors in the source code. Interpreters introduce a certain level of machine independence because no specific machine code is generated. The important thing from a scripting point of view, as we see in a moment, is interpreters allow the variable type to change dynamically. Because the user program is reexamined constantly during execution, variables do not need to have fixed types. This is much harder to accomplish with compilers because semantic analysis is done at compile time.

From this list, we can conclude interpreters are better suited for the development process, and compiled programs are better suited for production use. Because of this, for some languages, you can find both an interpreter and a compiler. This means you can reap all the benefits of interpreters in the development phase and then compile a final version of the program for a specific platform to gain better performance. Many of todays interpreted languages are not interpreted purely. Rather, they use a hybrid compiler-interpreter approach, as shown in Figure 1.3.

Source code

Compiler

Intermediate language code

External libraries

Interpreter

Result

FIGURE 1.3

Hybrid compiler-interpreter architecture

12

SCRIPTING

IN JAVA

In this model, the source code is first compiled to some intermediate code (such as Java bytecode), which is then interpreted. This intermediate code is usually designed to be very compact (it has been compressed and optimized). Also, this language is not tied to any specific machine. It is designed for some kind of virtual machine, which could be implemented in software. Basically, the virtual machine represents some kind of processor, whereas this intermediate code (bytecode) could be seen as a machine language for this processor. This hybrid approach is a compromise between pure interpreted and compiled languages, due to the following characteristics:
I

Because the bytecode is optimized and compact, interpreting overhead is minimized compared with purely interpreted languages. The platform independence of interpreted languages is inherited from purely interpreted languages because the intermediate code could be executed on any host with a suitable virtual machine.

Lately, just-in-time compiler technology has been introduced, which allows developers to compile bytecode to machine-specific code to gain performance similar to compiled languages. I mention this technology throughout the book, where applicable.

Source Code in Production


As some people have pointed out, you should use a scripting language to write user-readable and modifiable programs that perform simple operations and control the execution of other programs. In this scenario, source code should be available in the production system at runtime, so programs are delivered not in object code, but in plain text files (scripts) in their original source. From our previous discussion of interpreters, it is obvious this holds true for purely interpreted languages. Because scripting languages are interpreted, we can say this rule applies to them as well. But because some of them use a hybrid compilation-interpretation strategy, it is possible to deliver the

CHAPTER 1

13

program in intermediate bytecode form. The presence of the bytecode improves execution speed because no compilation process is required. The usual approach is to deliver necessary libraries in the bytecode and not the program itself. This way, execution speed is improved, and the program source is still readable in production. Some of the compiler-interpreter languages cache in the file the bytecode for the script on its first execution. On every following script execution, if the source hasnt been changed, the interpreter uses the cached bytecode, improving the startup speed required to execute the script. As such, the presence of source code in the production environment is one of the characteristics of scripting languages, although you can omit it for performance reasons or if you want to keep your source code secret.

Typing Strategies
Before I start a discussion on typing strategies implemented in different programming languages, I have to explain what types are. There is no simple way to explain what typing is because its definition depends on the context in which it is used. Also, a whole branch of mathematics is dedicated to this issue. It is called type theory, and its proponents have the following saying, which emphasizes their attitude toward the importance of this topic: Design the type system correctly, and the language will design itself. To put it simply, types are metadata that describe the data stored in some variable. Types specify what values can be stored in certain variables, as well as the operations that can be performed on them. Type constraints determine how we can handle and operate a certain variable. For example, what happens when you add the values of one variable to those of another depends on whether the variables are integers, floats, Booleans, or strings. A programming languages type system could classify the value

14

SCRIPTING

IN JAVA

hello as a string and the value 7 as a number. Whether you

can mix strings with numbers in this language depends on the languages type policy. Some types are native (or primitive), meaning they are built into the language. The usual representatives of this type category are Booleans, integers, floats, characters, and even strings in some languages. These types have no visible internal structure. Other types are composite, and are constructed of primitive types. In this category, we have structures and various so-called container types, such as lists, maps, and sets. In some languages, string is defined as a list of characters, so it can be categorized as a composite type. In object-oriented languages, developers got the opportunity to create their own types, also known as classes. This type category is called user-defined types. The big difference between structures and classes is with classes, you define not just the structure of your complex data, but also the behavior and possible operations you can perform with it. This categorizes every class as a single type, where structures (in C, for example) are one type. Type systems provide the following major benefits:
I

SafetyType systems are designed to catch the majority of type-misuse mistakes made by developers. In other words, types make it practically impossible to code some operations that cannot be valid in a certain context. OptimizationAs I already mentioned, languages that employ static typing result in programs with betteroptimized machine code. That is because early type checks provide useful information to the compiler, making it easier to allocate optimized space in memory for a certain variable. For example, there is a great difference in memory usage when you are dealing with a Boolean variable versus a variable containing some random text. AbstractionTypes allow developers to make better abstractions in their code, enabling them to think about programs at a higher level of abstraction, not bothering

CHAPTER 1

15

with low-level implementation of those types. The most obvious example of this is in the way developers deal with strings. It is much more useful to think of a string as a text value rather than as a byte array.
I

ModularityTypes allow developers to create application programming interfaces (APIs) for the subsystems used to build applications. Typing localizes the definitions required for interoperability of subsystems and prevents inconsistencies when those subsystems communicate. DocumentationUse of types in languages can improve the overall documentation of the code. For example, a declaration that some methods arguments are of a specific type documents how that method can be used. The same is true for return values of methods and variables.

Now that we know the basic concepts of types and typing systems, we can discuss the type strategies implemented in various languages. We also discuss how the choice of implemented typing system defines languages as either scripting (dynamic) or static.

DYNAMIC TYPING
The type-checking process verifies that the constraints introduced by types are being respected. System-programming languages traditionally used to do type checking at compile time. This is referred to as static typing. Scripting languages force another approach to typing. With this approach, type checking is done at runtime. One obvious consequence of runtime checking is all errors caused by inappropriate use of a type are triggered at runtime. Consider the following example:
x = 7 y = hello world z = x + y

This code snippet defines an integer variable, x, and a string variable, y, and then tries to assign a value for the z variable that is the sum of the x and y values. If the language has not

16

SCRIPTING

IN JAVA

defined an operator, +, for these two types, different things happen depending on whether the language is statically or dynamically typed. If the language was statically typed, this problem would be discovered at compile time, so the developer would be notified of it and forced to fix it before even being able to run the program. If the language was dynamically typed, the program would be executable, but when it tried to execute this problematic line, a runtime error would be triggered. Dynamic typing usually allows a variable to change type during program execution. For example, the following code would generate a compile-time error in most statically typed programming languages:
x = 7 x = Hello world

On the other hand, this code would be legal in a purely dynamic typing language. This is simply because the type is not being misused here. Dynamic typing is usually implemented by tagging the variables. For example, in our previous code snippet, the value of variable x after the first line would be internally represented as a pair (7, number). After the second line, the value would be internally represented as a pair (Hello world, string). When the operation is executed on the variable, the type is checked and a runtime error is triggered if the misuse is discovered. Because no misuse is detected in the previous example, the code snippet runs without raising any errors. I comprehensively discuss the pros and cons of these approaches later in this chapter, but for now, it is important to note a key benefit of dynamic typing from the developers point of view. Programs written in dynamically typed languages tend to be much shorter than equivalent solutions written in statically typed languages. This is an implication of the fact that developers have much more freedom in terms of expressing their ideas when they are not constrained by a strict type system.

CHAPTER 1

17

WEAK TYPING
There is yet another categorization of programming-language typing strategy. Some languages raise an error when a programmer tries to execute an operation on variables whose types are not suitable for that operation (type misuse). These languages are called strongly typed languages. On the other hand, weakly typed languages implicitly cast (convert) a variable to a suitable type before the operation takes place. To clarify this, lets take a look at our first example of summing a number and string variable. In a strongly typed environment, which most system-programming languages deploy, this operation results in a compile-time error if no operator is defined for these types. In a weakly typed language, the integer value usually would be converted to its string representative (7 in this case) and concatenated to the other string value (supposing that the + operator represents string concatenation in this case). The result would be a z variable with the 7HelloWorld value and the string type. Most scripting languages tend to be dynamic and weakly typed, but not all of them use these policies. For example, Python, a popular scripting language, employs dynamic typing, but it is strongly typed. We discuss in more detail the strengths and weaknesses of these typing approaches, and how they can fit into the overall system architecture, later in this chapter and in Chapter 2.

Data Structures
For successful completion of common programming tasks, developers usually need to use different complex data structures. The presence of language mechanisms for easy handling of complex data structures is in direct connection to developers efficiency. Scripting languages generally provide more powerful and flexible built-in data types than traditional system-programming languages. It is natural to see data structures such as lists, sets, maps, and so on, as native data types in such languages.

18

SCRIPTING

IN JAVA

Of course, it is possible to implement an arbitrary data structure in any language, but the point is these data structures are embedded natively in language syntax making them much easier to learn and use. Also, without this standard implementation, novice developers are often tempted to create their own solution that is usually not robust enough for production use. As an example, lets look at Python, a popular dynamic language with lists and maps (also called dictionaries) as its native language type. You can use these structures with other language constructs, such as a for loop, for instance. Look at the following example of defining and iterating a simple list:
list = [Mike, Joe, Bruce] for item in list : print item

As you can see, the Python code used in this example to define a list is short and natural. But more important is the for loop, which is designed to naturally traverse this kind of data. Both of these features make for a comfortable programming environment and thus save some time for developers. Java developers may argue that Java collections provide the same capability, but prior to J2SE 1.5, the equivalent Java code would look like this:
String[] arr = new String[]{Mike, Joe, Bruce}; List list = Arrays.asList(arr); for (Iterator it = list.iterator(); it.hasNext(); ) { System.out.println(it.next()); }

Even for this simple example, the Java code is almost twice as long as and is much harder to read than the equivalent Python code. In J2SE 1.5, Java got some features that brought it closer to these scripting concepts. With the more flexible for loop, you could rewrite the preceding example as follows:
String[] arr = new String[]{Mike, Joe, Bruce}; List list = Arrays.asList(arr); for (String item : list) { System.out.println(item); }

CHAPTER 1

19

With this in mind, we can conclude data structures are an important part of programming, and therefore native language support for commonly used structures could improve developers productivity. Many scripting languages come with flexible, built-in data structures, which is one of the reasons why they are often categorized as human-oriented.

Code as Data
The code and data in compiled system programming languages are two distinct concepts. Scripting languages, however, attempt to make them more similar. As I said earlier, programs (code) in scripting languages are kept in plain text form. Language interpreters naturally treat them as ordinary strings.

EVALUATION
It is not unusual for the commands (built-in functions) in scripting languages to evaluate a string (data) as language expression (code). For example, in Python, you can use the eval() function for this purpose:
x = 9 eval(print x + 7)

This code prints 16 on execution, meaning the value of the variable x is embedded into the string, which is evaluated as a regular Python program. More important is the fact that scripted programs can generate new programs and execute them on the fly. Look at the following Python example:
temp = open(temp.py, w) temp.write(print x + 7) temp.close() x = 9 execfile(temp.py)

In this example, we created a file called temp.py, and we wrote a Python expression in it. At the end of the snippet, the execfile() command executed the file, at which point 16 was displayed on the console.

20

SCRIPTING

IN JAVA

This concept is natural to interpreted languages because the interpreter is already running on the given host executing the current script. Evaluation of the script generated at runtime is not different from evaluation of other regular programs. On the other hand, for compiled languages this could be a challenging task. That is because a compile/link phase is introduced during conversion of the source code to the executable program. With interpreted languages, the interpreter must be present in the production environment, and with compiled languages, the compiler (and linker) is usually not part of the production environment.

CLOSURES
Scripting languages also introduce a mechanism for passing blocks of code as method arguments. This mechanism is called a closure. A good way to demonstrate closures is to use methods to select items in a list that meet certain criteria. Imagine a list of integer values. We want to select only those values greater than some threshold value. In Ruby, a scripting language that supports closures, we can write something like this:
threshold = 10 newList = orig.select {|item| item > threshold}

The select() method of the collection object accepts a closure, defined between the {}, as an argument. If parameters must be passed, they can be defined between the ||. In this example, the select() method iterates over the collection, passing each item to the closure (as an item parameter) and returning a collection of items for which the closure returned true. Another thing worth noting in this example is closures can refer to variables visible in the scope in which the closure is created. Thats why we could use the global threshold value in the closure. Closures in scripting languages are not different from any other data type, meaning methods can accept them as parameters and return them as results.

CHAPTER 1

21

FUNCTIONS AS METHOD ARGUMENTS


Many scripting languages, even object-oriented ones, introduce standalone functions as so-called first-class language citizens. Even if you do not have true support for closures, you can pass your functions as method arguments. The Python language, for example, defines a filter() function that accepts a list and the function to be executed on every item in the list:
def over(item) : threshold = 10 return item > threshold newList = filter(over, orig)

In this example, we defined the over() function, which basically does the same job as our closure from the previous example. Next, we called the filter() function and passed the over() function as the second argument. Even though this mechanism is not as convenient as closures are, it serves its purpose well (and that is to pass blocks of code as data around the application). Of course, you can achieve similar functionality in other nonscripting languages. For example, Java developers have the concept of anonymous inner classes serving the same purpose. Lets implement a similar solution using this approach:
package net.scriptinginjava.ch1; import import import import java.util.ArrayList; java.util.Arrays; java.util.Iterator; java.util.List;

interface IFilter { public boolean filter(Integer item); } public class Filter { private static List select(List list, IFilter filter) { List result = new ArrayList(); for (Iterator it = list.iterator(); it.hasNext();) { Integer item = (Integer)it.next(); if (filter.filter(item)) {

22

SCRIPTING

IN JAVA

result.add(item); } } return result; } public static void main(String[] args) { Integer[] arr = new Integer[]{ new Integer(5), new Integer(7), new Integer(13), new Integer(32) }; List orig = Arrays.asList(arr); List newList = select(orig, new IFilter() { private Integer threshold = new Integer(10); public boolean filter(Integer item) { return item.compareTo(threshold) > 0; } } ); System.out.println(newList); } }

NOTE

Some closure proponents say that the existence of this named interface breaks the anonymous concept at the beginning.

First we defined the IFilter interface with a filter() method that returns a Boolean value indicating whether the condition is satisfied. Our Filter class contains a select() method equal to the methods we saw in the earlier Ruby and Python examples. It accepts a list to be handled and the implementation of the IFilter interface that filters the values we want in our new list. At the end, we implement the IFilter interface as the anonymous inner class in the select() method call. As a result, the program prints this result list to the screen:
[13, 32]

From this example, we can see even though a similar concept is possible in system-programming languages, the syntax is much more complex. This is an important difference because the natural syntax for some functionality leads to its frequent use, in practice. Closures have simple syntax for passing the

CHAPTER 1

23

code around the application. That is why you see closures used more often in languages that naturally support them than you see similar structures in other languages (anonymous inner classes in Java, for example). Hopefully, closures will be added in Java SE 7, which will move Java one step closer to the flexibility of scripting languages.

Summary
In this section of the chapter, I discussed some basic functional characteristics of scripting languages. Many experts tend to categorize a language as scripting or system programming, not by these functional characteristics but by the programming style and the role the language plays in the system. However, these two categorizations are not independent, so to understand how scripting can fit into your development process, it is important to know the functional characteristics of the scripting language and the implications of its design. The differences between system-programming and scripting languages are described later in this chapter, helping us to understand how these two approaches can work together to create systems that feature the strengths of both programming styles. It is important to note that the characteristics weve discussed thus far are not independent among each other. For example, whether to use static or dynamic typing depends on when the type checking is done. It is hard to implement dynamic typing in a strictly compiled environment. Thus, interpreter and dynamic typing somehow fit naturally together and are usually employed in scripting environments. The same is true for the compiler and static typing found in system-programming environments. The similar is true for the generation and execution of other programs, which is a natural thing to do in interpreted environments and is not very easy (and thus is rarely done) in compiled environments. To summarize, these characteristics are usually found in scripting programming environments. Not all languages support all the features described earlier, which is a decision driven by

24

SCRIPTING

IN JAVA

the primary domain for which the language is used. For example, although Python is a dynamic language, it introduces strong typing, making it more resistible to type misuse and more convenient for development of larger applications. These characteristics should serve only as a marker when exploring certain languages and their possible use in your development process. More important is the languages programming style, a topic we discuss shortly.

Scripting Languages and Virtual Machines


A recent trend in programming language design is the presence of a virtual machine as one of the vital elements of programming platforms. One of the main elements of the Java Runtime Environment (JRE) is the virtual machine that interprets bytecode and serves as a layer between the application and operating systems. A virtual machine serves as a layer between the application and operating systems in Microsofts .NET platform as well. Lets now summarize briefly how the JRE works. Java programs contained in java extension source files are compiled to bytecode (files with a class extension). As I said earlier, the purpose of bytecode is to provide a compact format for intermediate code and support for platform independence. The JVM is a virtual processor, and like all other processors, it interprets codebytecode in this case. This is a short description of the JRE, but it is needed for our further discussion. You can find a more comprehensive description at the beginning of Chapter 3, Scripting Languages Inside the JVM. Following this, we can say Java is a hybrid compiled-interpreted language. But even with this model, Java cannot be characterized as a scripting language because it lacks all the other features mentioned earlier. At this point, you are probably asking what this discussion has to do with scripting languages. The point is many modern scripting languages follow the same hybrid concept. Although programs are distributed in script form and are interpreted at

CHAPTER 1

25

runtime, the things going on in the background are pretty much the same. Lets look at Python, for example. The Python interpreter consists of a compiler that compiles source code to the intermediate bytecode, and the Python Virtual Machine (PVM) that interprets this code. This process is being done in the background, leaving the impression that the pure Python source code has been interpreted. If the Python interpreter has write privileges on the host system, it caches the generated bytecode in files with a pyc extension (the py extension is used for the scripts or source code). If that script had not been modified since its previous execution, the compilation process would be skipped and the virtual machine could start interpreting the bytecode at once. This could greatly improve the Python scripts startup speed. Even if the Python interpreter has no write privileges on the system and the bytecode was not written in files, this compilation process would still be performed. In this case, the bytecode would be kept in memory. From this discussion, we can conclude virtual machines are one of the standard parts of modern scripting languages. So our original dilemma remains. Should we use languages that enforce a certain programming paradigm, and if so, how do we use them? The dynamic and weak typing, closures, complex built-in data structures, and so on, could be implemented in a runtime environment with the virtual machine. There is nothing to restrict the use of a dynamic (scripting) language on the virtual machines designed for languages such as Java and C#. As long as we implement the compiler appropriate for the target virtual machines intermediate bytecode, we will receive all the features of the scripting language in this environment. Doing this, we could benefit from the strengths of both the system-programming approach of Java, and the scripting programming model in our software development process. We focus on projects that bring scripting languages closer to the Java platform later in this book. Also, we discuss where its appropriate to apply the scripting style of development with traditional Java programming. Before we cover these topics, though, lets take a look at how scripting and system programming compare.

NOTE

Python programs can be distributed in bytecode format, keeping the source code out of the production environment.

26

SCRIPTING

IN JAVA

A Comparison of Scripting and System Programming


Every decision made during the language design process is directly related to the programming style used in that language and its usability in the development process. In this section, I do not intend to imply one style is better than the other is. Instead, my objective is to summarize the strengths and weaknesses of both approaches so that we can proceed to Chapter 2, where I discuss how best to incorporate them into the development process.

Runtime Performance
It is clear programs written in system-programming languages have better runtime performance than equivalent scripts in most cases, for a few reasons:
I

The most obvious reason is the runtime presence of the interpreter in scripting languages. Source code analysis and transformation during runtime introduces additional overhead in terms of program execution. Another factor influencing runtime performance is typing. Because system-programming languages force strong static typing, machine code created by the compiler is more compact and optimized for the target machine.

The fact that the script could be compiled to intermediate bytecode makes these interpreter performance penalties more acceptable. But the machine code is definitely more optimized than the intermediate code. We have to take another point of view when talking about runtime performance, however. Many people approach runtime performance by asking which solution is faster. The more important question, which is often neglected, is whether a particular solution is fast enough. You must take into consideration the tradeoffs between the benefits and the runtime performance that each approach

CHAPTER 1

27

provides when you are thinking about applying a certain technology in your project. If the solution brings quality to your development process and still is fast enough, you should consider using it. A recent development trend supports this point of view. Many experts state you should not analyze performance without comparing it to measurements and goals. This leads to debate concerning whether to perform premature or prudent optimization. The latter approach assumes you have a flexible system, and only after youve conducted the performance tests and found the system bottlenecks should you optimize those parts of your code. Deciding whether scripting is suitable for some tasks in your development process must be driven by the same question. For instance, say you need to load a large amount of data from a file, and developing a system-programming solution to accomplish the task would take twice as long as developing a scripting approach. If both the system-programming and scripting solutions need 1 second to load the data and the interpreter required an additional 0.1 second to compile the script to the bytecode, you should consider scripting to be a fast enough solution for this task. As we see in a moment, scripts are much faster to write (because of the higher level of abstraction they introduce), and the end users of your project probably wouldnt even notice the performance advantage of the systemprogramming solution that took twice as much time to develop. If we take another point of view, we can conclude the startup cost of executing programs written in dynamic languages could be close to their compiled alternatives. The first important thing to note is the fact that bytecode is usually smaller than its equivalent machine code. Experts who support this point of view stress that processors have increased in speed much faster than disks have. This leads to the thinking that the in-memory operations of the just-in-time compilers (compiling the bytecode to the machine code) are not much more expensive than the operation of loading the large sequence of machine code from the disk into memory. To summarize, it is clear system-programming languages are faster than scripting languages. But if you dont need to be

28

SCRIPTING

IN JAVA

restricted by only one programming language, you should ask yourself another question: What is the best tool for this task? If the development speed is more important and the runtime performance of the scripting solution is acceptable, there is your answer.

Development Speed
I already mentioned dynamic languages lead to faster development processes. A few facts support this assertion. For one, a statement in a system-programming language executes about five machine instructions. However, a statement in a scripting language executes hundreds or even thousands of instructions. Certainly, this increase is partially due to the presence of the interpreter, but more important is the fact that primitive operations in scripting languages have greater functionality. For example, operations for matching certain patterns in text with regular expressions are as easy to perform as multiplying two integers. These more powerful statements and built-in data structures lead to a higher level of abstraction that language can provide, as well as much shorter code. Of course, dynamic typing plays an important role here too. The need to define each variable explicitly with its type requires a lot of typing, and this is time consuming from a developers perspective. This higher level of abstraction and dynamic typing allows developers to spend more time writing the actual business logic of the application than dealing with the language issues. Another thing speeding up the scripting development process is the lack of a compile (and linking) phase. Compilation of large programs could be time consuming. Every change in a program written in a system-programming language requires a new compile/link process, which could slow down development a great deal. In scripting, on the other hand, immediately after the code is written or changed, it can be executed (interpreted), leaving more time for the developer to actually write the code. As you can see, all the things that increase runtime performance, such as compilation and static typing, tend to slow

CHAPTER 1

29

down development and increase the amount of time needed to build the solution. That is why you hear scripting languages are more human oriented than machine oriented (which isnt the case with system-programming languages). To emphasize this point further, here is a snippet from David Aschers article titled Dynamic Languagesready for the next challenges, by design (www.activestate.com/Company/ NewsRoom/whitepapers_ADL.plex), which reflects the paradigm of scripting language design: The driving forces for the creation of each major dynamic language centered on making tasks easier for people, with raw computer performance a secondary concern. As the language implementations have matured, they have enabled programmers to build very efficient software, but that was never their primary focus. Getting the job done fast is typically prioritized above getting the job done so that it runs faster. This approach makes sense when one considers that many programs are run only periodically, and take effectively no time to execute, but can take days, weeks, or months to write. When considering networked applications, where network latency or database accesses tend to be the bottlenecks, the folly of hyper-optimizing the execution time of the wrong parts of the program is even clearer. A notable consequence of this difference in priority is seen in the different types of competition among languages. While system languages compete like CPU manufacturers on performance measured by numeric benchmarks such as LINPACK, dynamic languages compete, less formally, on productivity arguments and, through an indirect measure of productivity, on how fun a language is. It is apparently widely believed that fun languages correspond to more productive programmersa hypothesis that would be interesting to test.

Robustness
Many proponents of the system-programming approach say dynamic typing introduces more bugs in programs because there is no type checking at compile time. From this point of view, it is always good to detect programming errors as soon as

30

SCRIPTING

IN JAVA

possible. This is certainly true, but as we discuss in a moment, static typing introduces some drawbacks, and programs written in dynamically typed languages could be as solid as programs written in purely statically typed environments. This way of thinking leads to the theory that dynamically typed languages are good for building prototypes quickly, but they are not robust enough for industrial-strength systems. On the other side stand proponents of dynamic typing. From that point of view, type errors are just one source of bugs in an application, and programs free of type-error problems are not guaranteed to be free of bugs. Their attitude is static typing leads to code much longer and much harder to maintain. Also, static typing requires the developer to spend more of his time and energy working around the limitations of that kind of typing. Another implication we can glean from this is the importance of testing. Because a successful compilation does not guarantee your program will behave correctly, appropriate testing must be done in both environments. Or as best-selling Java author Bruce Eckel wrote in his book Thinking in Java (Prentice Hall): If its not tested, its broken. Because dynamic typing allows you to implement functionality faster, more time remains for testing. Those fine-grained tests could include testing program behavior for type misuse. Despite all the hype about type checking, type errors are not common in practice, and they are discovered quickly in the development process. Look at the most obvious example. With no types declared for method parameters, you could easily find yourself calling a method with the wrong order of parameters. But these kinds of errors are obvious and are detected immediately the next time the script is executed. It is highly unlikely this kind of error would make it to distribution if it was tested appropriately. Another extreme point of view says even statically typed languages are not typed. To clarify this statement, look at the following Java code:

CHAPTER 1

31

List list = new ArrayList(); list.add(new String(Hello)); list.add(new Integer(77)); Iterator it = list.iterator(); while (it.hasNext()) { String item = (String)it.next(); }

This code snippet would be compiled with no errors, but at execution time, it would throw a java.lang.ClassCastException. This is a classic example of a runtime type error. So what is the problem? The problem is objects lose their type information when they are going through more-generic structures. In Java, all objects in the container are of type java.lang.Object, and they must be converted to the appropriate type (class) as soon as they are released from the container. This is when inappropriate object casting could result in runtime type errors. Because many objects in the application are actually contained in a more-generic structure, this is not an irrelevant issue. Of course, there is a workaround for this problem in statically typed languages. One solution recently introduced in Java is called generics. With generics, you would write the preceding example as follows:
List list<String> = new ArrayList<String>(); list.add(new String(Hello)); list.add(new Integer(77)); Iterator<String> it = list.iterator(); while (it.hasNext()) { String item = it.next(); }

This way, you are telling the compiler only String objects can be placed in this container. An attempt to add an Integer object would result in a compilation error. This is a solution to this problem, but like all workarounds, it is not a natural approach. The fact that scripting programs are smaller and more readable by humans makes them more suitable for code review by a

32

SCRIPTING

IN JAVA

development team, which is one more way to ensure your application is correct. Guido van Rossum, the creator of the Python language, supported this view when he was asked in an interview whether he would fly an airplane controlled by software written in Python (www.artima.com/intv/strongweakP.html): Youll never get all the bugs out. Making the code easier to read and write, and more transparent to the team of human readers who will review the source code, may be much more valuable than the narrow-focused type checking that some other compiler offers. There have been reported anecdotes about spacecraft or aircraft crashing because of type-related software bugs, where the compilers werent enough to save you from the problems. This discussion is intended just to emphasize one thing: Type errors are just one kind of bug in a program. Early type checking is a good thing, but it is certainly not enough, so conducting appropriate quality assurance procedures (including unit testing) is the only way to build stable and robust systems. Many huge projects written purely in Python prove the fact that modern scripting languages are ready for building large and stable applications.

Maintenance
A few aspects of scripting make programs written in scripting languages easier to maintain. The first important aspect is the fact that programs written in scripting languages are shorter than their system-programming equivalents, due to the natural integration of complex data types, more powerful statements, and dynamic typing. Simple logic dictates it is easier to debug and add additional features to a shorter program than to a longer one, regardless of what programming language it was written in. Heres a more descriptive discussion on this topic, taken from the aforementioned Guido van Rossum interview (www.artima.com/intv/speed.html): This is all very informal, but I heard someone say a good programmer can reasonably maintain about 20,000 lines of code.

CHAPTER 1

33

Whether that is 20,000 lines of assembler, C, or some high-level language doesnt matter. Its still 20,000 lines. If your language requires fewer lines to express the same ideas, you can spend more time on stuff that otherwise would go beyond those 20,000 lines. A 20,000-line Python program would probably be a 100,000line Java or C++ program. It might be a 200,000-line C program, because C offers you even less structure. Looking for a bug or making a systematic change is much more work in a 100,000-line program than in a 20,000-line program. For smaller scales, it works in the same way. A 500-line program feels much different than a 10,000-line program. The counterargument to this is the claim that static typing also represents a kind of code documentation. Having every variable, method argument, and return result in a defined type makes code more readable. Although this is a valid claim when it comes to method and property declarations, it certainly is not important to document every temporary variable. Also, in almost every programming language you can find a mechanism and tools used to document your code. For example, Java developers usually use the Javadoc tool (http://java.sun.com/ j2se/javadoc/) to generate HTML documentation from specially formatted comments in source code. This kind of documentation is more comprehensive and could be used both in scripting and in system-programming languages. Also, almost every dynamically typed language permits explicit type declaration but does not force it. Every scripting developer is free to choose where explicit type declarations should be used and where they are sufficient. This could result in both a rapid development environment and readable, documented code.

Extreme Programming
In the past few years, many organizations adopted extreme programming as their software development methodology. The two basic principles of extreme programming are test-driven development (TDD) and refactoring.

34

SCRIPTING

IN JAVA

You can view the TDD technique as a kind of revolution in the way people create programs. Instead of performing the following: 1. Write the code. 2. Test it if appropriate. The TDD cycle incorporates these steps: 1. Write the test for certain program functionality. 2. Write enough code to get it to fail (API). 3. Run the test and watch it fail. 4. Write the whole functionality. 5. Run the code and watch all tests pass. On top of this development cycle, the extreme programming methodology introduces refactoring as a technique for code improvement and maintenance. Refactoring is the technique of restructuring the existing code body without changing its external behavior. The idea of refactoring is to keep the code design clean, avoid code duplication, and improve bad design. These changes should be small because that way, it is likely we will not break the existing functionality. After code refactoring, we have to run all the tests again to make sure the program is still behaving according to its design. I already stated tests are one way to improve our programs robustness and to prevent type errors in dynamically typed languages. From the refactoring point of view, interpreted languages offer benefits because they skip the compilation process during development. For applications developed using the system-programming language, after every small change (refactoring), you have to do compilation and run tests. Both of these operations could be time consuming on a large code base, so the fact that compilation could be omitted means we can save some time. Dynamic typing is a real advance in terms of refactoring. Usually, because of laziness or a lack of the big picture, a developer defines a method with as narrow an argument type as he needs at that moment. To reuse that method later, we have to

CHAPTER 1

35

change the argument type to some more general or complex structure. If this type is a concrete type or does not share the same interface as the one we used previously, we are in trouble. Not only do we have to change that method definition, but also the types of all variables passed to that method as the particular argument. In dynamically typed languages, this problem does not exist. All you need to do is change the method to handle this more general type. We could amortize these problems in system programming environments with good refactoring tools, which exist for most IDEs today. Again, the real benefit is speed of development. Because scripting languages enable developers to write code faster, they have more time to do appropriate unit testing and to write stub classes. A higher level of abstraction and a dynamic nature make scripted programs more convenient to change, so we can say they naturally fit the extreme programming methodology.

The Hybrid Approach


As we learned earlier in this chapter, neither systemprogramming nor scripting languages are ideal tools for all development tasks. System-programming languages have good runtime performance, but developing certain functionality and being able to modify that functionality later takes time. Scripting languages, on the other hand, are the opposite. Their flexible and dynamic nature makes them an excellent development environment, but at the cost of runtime performance. So the real question is not whether you should use a certain system-programming or scripting language for all your development tasks, but where and how each approach fits into your project. Considering todays diverse array of programming platforms and the many ways in which you can integrate them, there is no excuse for a programmer to be stuck with only one programming language. Knowing at least two languages could help you have a better perspective of the task at hand, and the appropriate tool for that task.

36

SCRIPTING

IN JAVA

You can find a more illustrative description of this principle in Bill Vennerss article, The Best Tool for the Job (www.artima.com/commentary/langtool.html): To me, attempting to use one language for every programming task is like attempting to use one tool for every carpentry task. You may really like screwdrivers, and your screwdriver may work great for a job like inserting screws into wood. But what if youre handed a nail? You could conceivably use the butt of the screwdrivers handle and pound that nail into the wood. The trouble is, a) you are likely to put an eye out, and b) you wont be as productive pounding in that nail with a screwdriver as you would with a hammer. Because learning a new programming language requires so much time and effort, most programmers find it impractical to learn many languages well. But I think most programmers could learn two languages well. If you program primarily in a systems language, find a scripting language that suits you and learn it well enough to use it regularly. I have found that having both a systems and a scripting language in the toolbox is a powerful combination. You can apply the most appropriate tool to the programming job at hand. So if we agree system-programming and scripting languages should be used together for different tasks in project development, two more questions arise. The first, and the most important one, is what tasks are suitable for a certain tool. The second question concerns what additional characteristics scripting languages should have to fit these development roles. Lets try to answer these two questions by elaborating on the most common roles (and characteristics) scripting languages had in the past. This gives us a clear vision of how we can apply them to the development challenges in Java projects today, which is the topic of later chapters.

CHAPTER 1

37

A Case for Scripting


To end our discussion of this topic, I quote John K. Ousterhout, the creator of the Tcl scripting language. In one of his articles (www.tcl.tk/doc/scripting.html), he wrote the following words: In deciding whether to use a scripting language or a system programming language for a particular task, consider the following questions: Is the applications main task to connect together pre-existing components? Will the application manipulate a variety of different kinds of things? Does the application include a graphical user interface? Does the application do a lot of string manipulation? Will the applications functions evolve rapidly over time? Does the application need to be extensible? Yes answers to these questions suggest that a scripting language will work well for the application. On the other hand, yes answers to the following questions suggest that an application is better suited to a system programming language: Does the application implement complex algorithms or data structures? Does the application manipulate large datasets (e.g., all the pixels in an image) so that execution speed is critical? Are the applications functions well-defined and changing slowly? You could translate Ousterhouts comments as follows: Dynamic languages are well suited for implementing application parts not defined clearly at the time of development, for wiring (gluing) existing components in a loosely coupled manner, and for implementing all those parts that have to be flexible and changeable over time. System languages, on the other hand, are

38

SCRIPTING

IN JAVA

a good fit for implementing complex algorithms and data structures, and for all those components that are well defined and probably wont be modified extensively in the future.

Conclusion
In this chapter, I explained what scripting languages are and discussed some basic features found in such environments. After that, I compared those features to system-programming languages in some key development areas. Next, I expressed the need for software developers to master at least one representative of both system-programming and scripting languages. And finally, I briefly described suitable tasks for both of these approaches. Before we proceed to particular technologies that enable usage of scripting languages in Java applications, we focus in more detail on the traditional roles of scripting languages. This is the topic of Chapter 2, and it helps us to better understand scripting and how it can be useful in the overall system infrastructure.

I S B N : 0 -321- 49193 -9

B U Y TH E b OO K TO DAY

DRAFT MANUSCRIPT
Books Available December 2007
This manuscript has been provided by Pearson Education at this early stage to create awareness for this upcoming book. IT HAS NOT BEEN COPYEdiTEd Or PrOOFrEAd YET; we trust that you will judge this book on technical merit, not on grammatical and punctuation errors that will be xed at a later stage. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent of the publisher. All Pearson Education books are available at a discount for corporate bulk purchases. For information on bulk discounts, please call (800) 428-5531.

Ajax Security

Billy Hoffman and Bryan Sullivan

Upper Saddle River, NJ Boston Indianapolis San Francisco New York Toronto Montreal London Munich Paris Madrid Capetown Sydney Tokyo Singapore Mexico City

Transparency in Ajax Applications

Myth: Ajax applications are black box systems, just like regular Web applications. If you are like most people, when you use a microwave oven, you have no idea how it actually works. You only know that if you put food in and turn the oven on, the food will get hot in a few minutes. By contrast, a toaster is fairly easy to understand. When youre using a toaster, you can just look inside the slots to see the elements getting hot and toasting the bread. A traditional Web application is like a microwave oven. Most users dont know how Web applications workand dont even care to know how they work. Furthermore, most users have no way to find out how a given application works even if they did care. Beyond the fundamentals, such as use of HTTP as a request protocol, there is no guaranteed way to determine the inner workings of a Web site. By contrast, an Ajax Web application is more like a toaster. While the average user may not be aware that the logic of the Ajax application is more exposed than that of the standard Web page, it is a simple matter for an advanced user (or an attacker) to look inside the toaster slots and gain knowledge about the internal workings of the application.

BLACK BOXES VERSUS WHITE BOXES


Web applications (and microwave ovens) are examples of black box systems. From the users perspective, input goes into the system, and then output comes out of the system, as illustrated in Figure 6-1. The application logic that processes the input and returns the output is abstracted from the user and is invisible to him.

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

?
Figure 6-1

The inner workings of a black box system are unknown to the user.

For example, consider a weather forecast Web site. A user enters his ZIP code into the application, and the application then tells him if the forecast calls for rain or sun. But how did the application gather that data? It may be that the application performs realtime analysis of current weather radar readings, or it may be that every morning a programmer watches the local television forecast and copies that into the system. Because the end user does not have access to the source code of the application, there is really no way for him to know.

S ECURITY N OTE There are, in fact, some situations in which an end user may be able to obtain the applications source code. These situations mostly arise from improper configuration of the Web server or insecure source code control techniques, such as storing backup files on production systems. Please review Chapter 3 for more information on these types of vulnerabilities.

White box systems behave in the opposite manner. Input goes into the system and output comes out of the system as before, but in this case the internal mechanisms (in the form of source code) are visible to the user (see Figure 6-2). Any interpreted script-based application, such as a batch file, macro, or (more to the point) a JavaScript application, can be considered a white box system. As we discussed in the previous chapter, JavaScript must be sent from the server to the client in its original, unencrypted source code form. It is a simple matter for a user to open this source code and see exactly what the application is doing.

BLACK BOXES VERSUS WHITE BOXES

Figure 6-2

The user can see the inner workings of a white box system.

It is true that Ajax applications are not completely white box systems; there is still a large portion of the application that executes on the server. However, they are much more transparent than traditional Web applications, and this transparency provides opportunities for hackers, as we will demonstrate over the course of the chapter. It is possible to obfuscate JavaScript, but this is different than encryption. Encrypted code is impossible to read until the correct key is used to decrypt it, at which point it is readable by anyone. Encrypted code cannot be executed until it is decrypted. On the other hand, obfuscated code is still executable as-is. All the obfuscation process accomplishes is to make the code more difficult to read by a human. The key phrases here are that obfuscation makes code more difficult for a human to read, while encryption makes it impossible, or at least virtually impossible. Someone with enough time and patience could still reverse-engineer the obfuscated code. As we saw in Chapter 2, Eve created a program to de-obfuscate JavaScript. In actuality, the authors created this tool, and it only took a few days. For this reason, obfuscation should be considered more of a speed bump than a roadblock for a hacker: It may slow a determined attacker down but it will not stop her. In general, white box systems are easier to attack than black box systems because their source code is more transparent. Remember that attackers thrive on information. A large percentage of the time a hacker spends attacking a Web site is not actually spent sending malicious requests, but rather analyzing it to determine how it works. If the application freely provides details of its implementation, this task is greatly simplified. Lets continue the weather forecasting Web site example and evaluate it from an application logic transparency point of view.

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

EXAMPLE: MYLOCALWEATHERFORECAST.COM
First, lets look at a standard, non-Ajax version of MyLocalWeatherForecast.com (see Figure 6-3).

Figure 6-3

A standard, nonAjax weather forecasting Web site

Theres not much to see from the rendered browser output, except that the server-side application code appears to be written in PHP. We know that because the filename of the Web page ends in.php. The next logical step an attacker would take would be to view the page source, so we will do the same.
<html> <head> <title>Weather Forecast</title> </head> <body> <form action="/weatherforecast.php" method="POST"> <div> Enter your ZIP code: <input name="ZipCode" type="text" value=30346 /> <input id="Button1" type="submit" value="Get Forecast" /> </div> </form> </body> </html>

BLACK BOXES VERSUS WHITE BOXES

Theres not much to see from the page source code either. We can tell that the page uses the HTTP POST method to post the user input back to itself for processing. As a final test, we will attach a network traffic analyzer (also known as a sniffer) and examine the raw response data from the server.
HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Sat, 16 Dec 2006 18:23:12 GMT Connection: close Content-type: text/html X-Powered-By: PHP/5.1.4 <html> <head> <title>Weather Forecast</title> </head> <body> <form action="/weatherforecast.php" <div> Enter your ZIP code: <input name="ZipCode" type="text" <input id="Button1" type="submit" <br /> The weather for December 17, 2006 </div> </form> </body> </html>

method="POST">

value=30346 /> value="Get Forecast" /> for 30346 will be sunny.

The HTTP request headers give us a little more information to work with. The header XPowered-By: PHP/5.1.4 confirms that the application is indeed using PHP for its serverside code. Additionally, we now know which version of PHP the application uses (5.1.4). We can also see from the Server: Microsoft-IIS/5.1 header that the application uses Microsoft Internet Information Server (IIS) version 5.1 as the Web server. This implicitly tells us that Microsoft Windows XP Professional is the servers operating system, because IIS 5.1 only runs on XP Professional. So far, we have collected a modest amount of information regarding the weather forecast site. We know what programming language is used to develop the site and the particular version of that language. We know which Web server and operating system are being used. These tidbits of data seem innocent enoughafter all, what difference could it make to a hacker if he knew that a Web application was running on IIS versus Tomcat? The answer is simple: time. Once the hacker knows that a particular technology is being

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

used, he can focus his efforts on cracking that piece of the application and avoid wasting time by attacking technologies he now knows are not being used. As an example, knowing that XP Professional is being used as the operating system allows the attacker to omit attacks that could only succeed against Solaris or Linux operating systems. He can concentrate on making attacks that are known to work against Windows. If he doesnt know any Windows-specific attacks (or IIS-specific attacks, or PHP-specific attacks, etc,) it is a simple matter to find examples on the Internet. S ECURITY N OTE Disable HTTP response headers that reveal implementation or configuration details of your Web applications. The Server and X-Powered-By headers both reveal too much information to potential attackers and should be disabled. The process for disabling these headers varies among different Web servers and application frameworks; for example, Apache users can disable the Server header with a configuration setting, while IIS users can use the RemoveServerHeader feature of Microsofts UrlScan Security Tool. This feature has also been integrated natively into IIS since version 6. For maximum security, also remap your applications file extensions to custom types. It does little good to remove the X-Powered-By: ASP.NET header if your Web pages end in .aspx extensions. Hiding application details like these doesnt guarantee that your Web site wont be hacked, but it will make the attacker work that much harder to do it. He might just give up and attack someone else.

EXAMPLE: MYLOCALWEATHERFORECAST.COM AJAXIFIED


Now that we have seen how much of the internal workings of a black box system can be uncovered, lets examine the same weather forecasting application after it has been converted to Ajax. The new site is shown in Figure 6-4. The new Web site looks the same as the old when viewed in the browser. We can still see that PHP is being used because of the file extension, but there is no new information yet. However, when we view the page source what can we learn?
<html> <head> <script type="text/javascript"> var httpRequest = getHttpRequest(); function getRadarReading() { // access the web service to get the radar reading var zipCode = document.getElementById(ZipCode).value;

BLACK BOXES VERSUS WHITE BOXES

Figure 6-4

The Ajax-based weather forecast site

httpRequest.open("GET", "weatherservice.asmx?op=GetRadarReading&zipCode=" + zipCode, true); httpRequest.onreadystatechange = handleReadingRetrieved; httpRequest.send(null); } function handleReadingRetrieved() { if (httpRequest.readyState == 4) { if (httpRequest.status == 200) { var radarData = httpRequest.responseText; // process the XML retrieved from the web service var xmldoc = parseXML(radarData); var weatherData = xmldoc.getElementsByTagName("WeatherData")[0]; var cloudDensity = weatherData.getElementsByTagName ("CloudDensity")[0].firstChild.data; getForecast(cloudDensity); } } } function getForecast(cloudDensity) { httpRequest.open("GET", "forecast.php?cloudDensity=" + cloudDensity,

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

true); httpRequest.onreadystatechange = handleForecastRetrieved; httpRequest.send(null); } function handleForecastRetrieved() { if (httpRequest.readyState == 4) { if (httpRequest.status == 200) { var chanceOfRain = httpRequest.responseText; var displayText; if (chanceOfRain >= 25) { displayText = "The forecast calls for rain."; } else { displayText = "The forecast calls for sunny skies."; } document.getElementById(Forecast).innerHTML = displayText; } } } function parseXML(text) { if (typeof DOMParser != "undefined") { return (new DOMParser()).parseFromString(text, "application/xml"); } else if (typeof ActiveXObject != "undefined") { var doc = new ActiveXObject("MSXML2.DOMDocument"); doc.loadXML(text); return doc; } } </script> </head> </html>

Aha! Now we know exactly how the weather forecast is calculated. First, the function getRadarReading makes an asynchronous call to a Web service to obtain the current radar data for the given ZIP code. The radar data XML returned from the Web service is parsed apart (in the handleReadingRetrieved function) to find the cloud density reading. A second asynchronous call (getForecast) passes the cloud density value back to the server. Based on this cloud density reading, the server determines tomorrows chance of rain. Finally, the client displays the result to the user and suggests whether she should

BLACK BOXES VERSUS WHITE BOXES

take an umbrella to work. Just from viewing the client-side source code, we now have a much better understanding of the internal workings of the application. Lets go one step further and sniff some of the network traffic.
HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Sat, 16 Dec 2006 18:54:31 GMT Connection: close Content-type: text/html X-Powered-By: PHP/5.1.4 <html> <head> <script type="text/javascript"> </html>

Sniffing the initial response from the main page didnt tell us anything that we didnt already know. We will leave the sniffer attached while we make an asynchronous request to the radar reading Web service. The server responds in the following manner:
HTTP/1.1 200 OK Server: Microsoft-IIS/5.1 Date: Sat, 16 Dec 2006 19:01:43 GMT X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private, max-age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 301 <?xml version="1.0" encoding="utf-8"?> <WeatherData> <Latitude>33.76</Latitude> <Longitude>-84.4</Longitude> <CloudDensity>0</CloudDensity> <Temperature>54.2</Temperature> <Windchill>54.2</Windchill> <Humidity>0.83</Humidity> <DewPoint>49.0</DewPoint> <Visibility>4.0</Visibility> </WeatherData>

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

This response gives us some new information about the Web service. We can tell from the X-Powered-By header that it uses ASP.NET, which might help an attacker as described earlier. More interestingly, we can also see from the response that much more data than just the cloud density reading is being retrieved. The current temperature, wind chill, humidity, and other weather data are being sent to the client. The client-side code is discarding these additional values, but they are still plainly visible to anyone with a network traffic analyzer.

COMPARISON CONCLUSIONS
Comparing the amount of information gathered on MyLocalWeatherForecast.com before and after its conversion to Ajax, we can see that the new Ajax-enabled site discloses everything that the old site did, as well as some additional items. The comparison is presented on Table 6-1.
Table 6-1

Information disclosure in Ajax vs. Non-Ajax applications


Non-Ajax Ajax

Information Disclosed

Source code language Web server Server operating system Additional subcomponents Method signatures Parameter data types

Yes Yes Yes No No No

Yes Yes Yes Yes Yes Yes

THE WEB APPLICATION AS AN API


The effect of MyLocalWeatherForecast.coms shift to Ajax is that the client-side portion of the application (and by extension, the user) has more visibility into the server-side components. Before, the system functioned as a black box. Now, the box is becoming clearer; the processes are becoming more transparent. Figure 6-5 shows the visibility of the old MyLocalWeatherForcast.com site.

10

THE WEB APPLICATION AS AN API

Visibility

User

Get weather forecast

weatherforecast.php

Figure 6-5

Client visibility of (non-Ajax) MyLocalWeatherForecast.com

In a sense, MyLocalWeatherForecast.com is just an elaborate application programming interface (API). In the non-Ajax model (see Figure 6-6), there is only one publicly exposed method in the API, Get weather forecast.
Visibility Obtain radar data Process radar data weatherservice.asmx Create forecast weatherforecast.php

User

forecast.php

Figure 6-6

Client visibility of Ajax MyLocalWeatherForecast.com

Not only did our API get a lot bigger (three methods instead of one), but its granularity increased as well. Instead of one, big do it function, we can see the individual subroutines that combine to calculate the result output. Furthermore, in many real-world scenarios, the JavaScript client-side code is not defined in each individual page on an as-needed basis. Instead, all of the client-side JavaScript functions used on any page are collected into a single, monolithic script library that is then referenced by each page that uses it.
<script src="ajaxlibrary.js"></script>

11

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

This architecture makes it easier for the site developers to maintain the code, because they now only have to make changes in a single place. It can save bandwidth as well, because a browser will download the entire library only once and then cache it for later use. Of course, the downside of this is that the entire API can now be exposed after only a single request from a user. The user basically asks the server, Tell me everything you can do, and the server answers with a list of actions. As a result, a potential hacker can now see a much larger attack surface, and his task of analyzing the application is made much easier as well. The flow of data through the system is more evident, and data types and method signatures are also visible.

DATA TYPES AND METHOD SIGNATURES


Knowing the arguments data types can be especially useful to an attacker. For example, if an attacker finds that a given parameter is an unsigned, 16-bit integer, he knows that valid values for that parameter range from 0 to 65,535 (216-1). However, the attacker is not constrained to send only valid values. Because the method arguments are sent as strings over the wire, the attacker is not even constrained to send valid data types. He may send a negative value, or a value greater than 65,535, to try to overflow or underflow the value. He may send a nonnumeric value just to try to cause the server to generate an error message. Error messages returned from a Web server often contain sensitive information, such as stack traces and lines of source code. Nothing makes analyzing an application easier than having its server-side source code! It may be useful just to know which pieces of data are used to calculate results. For example, in MyLocalWeatherForecast.com, the forecast is determined solely from the current cloud density and not from any of the other current weather variables such as temperature or dew point. The usefulness of this information can vary from application to application. Knowing that the current humidity does not factor into the weather forecast at MyLocalWeatherForecast.com may not help a hacker penetrate the site, but knowing that a persons employment history does not factor into a loan application decision at an online bank may.

SPECIFIC SECURITY MISTAKES


Beyond the general danger of revealing application logic to potential attackers, there are specific mistakes that programmers make when writing client-side code that can open their applications to attack.

12

SPECIFIC SECURITY MISTAKES

IMPROPER AUTHORIZATION
Lets return to MyLocalWeatherForecast.com. MyLocalWeatherForecast.com has an administration page, where site administrators can check usage statistics. The site requires administrative authorization rights in order to access this page. Site users and other prying eyes are, hence, prevented from viewing the sensitive content. Because the site already used Ajax to retrieve the weather forecast data, the programmers continued this model and used Ajax to retrieve the administrative data: They added client-side JavaScript code that pulls the usage statistics from the server, as shown in Figure 6-7.
scriptlibrary.js

weatherforecast.php GetRadarReading

User

GetUsageStatistics admin.php

Administrator

Figure 6-7

Intended usage of the Ajax administration functionality

Unfortunately, while the developers at MyLocalWeatherForecast.com were diligent about restricting access to the administration page (admin.php), they neglected to restrict access to the server API that provides the actual data to that page. While an attacker would be blocked from accessing admin.php, there is nothing to prevent him from calling the GetUsageStatistics function directly. This technique is illustrated in Figure 6-8. There is no reason for the hacker to try to gain access to admin.php. He can dispense with the usual, tedious authorization bypass attacks like hijacking a legitimate users session or guessing a username and password through brute force. Instead, he can simply ask the server for the administrative data without having to go to the administrative page, just as Eve did in her attack on HighTechVacations.net in Chapter 2. The programmers at MyLocalWeatherForecast.com never intended the GetUsageStatistics function to be called from any page other than admin.php. They might not have even realized that it could be called from any other page. Nevertheless, their application has been hacked and they are to blame.

13

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

scriptlibrary.js

admin.php

X
GetUsageStatistics

Attacker

Figure 6-8 Hacking the administration functionality by directly accessing the client-side JavaScript function

S ECURITY N OTE In this case, it was easy for the attacker to discover the GetUsageStatistics function and call it, because it was defined in a shared library referenced by both the main user page weatherforecast.php and the administration page admin.php. However, even if GetUsageStatistics were to be removed from the shared library and defined only in admin.php, this would not change the fact that an attacker could still call the server method directly if he ever found out about its existence. Hiding the method is not a substitute for appropriate authorization. Hiding the method is an example of relying on security through obscurity and is a dangerous approach to take. The problems with depending on obscurity are discussed later in this chapter.

Some of the worst cases of improperly authorized API methods come from sites that were once standard Web applications but were later converted to Ajax-enabled applications. You must take care when Ajaxifying applications in order to avoid accidentally exposing sensitive or trusted server-side functionality. In one real-world example of this, the developers of a Web framework made all their user management functionality available through Ajax calls. Just like our fictional developers at MyLocalWeatherForecast.com, they neglected to add authorization to the server code. As a result, any attacker could easily add new users to the system, remove existing users, or change users passwords at will.

14

SPECIFIC SECURITY MISTAKES

S ECURITY N OTE When converting an existing application to Ajax, remember to add authorizationchecking code to newly-exposed methods. Functionality that was intended to be accessed only from certain pages will now be available everywhere. As a result, you can no longer rely on the authorization mechanisms of the page code. Each public method must now check a users authorization.

OVERLY GRANULAR SERVER API


The lack of proper authorization in the previous section is really just a specific case of a much broader and more dangerous problem: the overly granular server API. This problem occurs when programmers expose a server API and assume that the only consumers of that API will be the pages of their applications and that those pages will always use that API in exactly the way that the programmers intended. The truth is, an attacker can easily manipulate the intended control flow of any client-side script code. Lets revisit the online music store example from Chapter 1, Introduction to Ajax Security.
function purchaseSong(username, password, songId) { // first authenticate the user var authenticated = checkCredentials(username, password); if (authenticated == false) { alert(The username or password is incorrect.); return; } // get the price of the song var songPrice = getSongPrice(songId); // make sure the user has enough money in his account if (getAccountBalance(username) < songPrice) { alert(You do not have enough money in your account.); return; } // debit the users account debitAccount(username, songPrice); // start downloading the song to the client machine downloadSong(songId); }

15

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

The intended flow of this code is straightforward. First the application checks the users username and password, then it retrieves the price of the selected song and makes sure the user has enough money in his account to purchase it. Next, it debits the users account for the appropriate amount, and finally it allows the song to download to the users computer. All of this works fine for a legitimate user. But lets think like our hacker Eve would and attach a JavaScript debugger to the page to see what kind of havoc we can wreak. We will start with the debugger Firebug for Firefox. Firebug will display the raw HTML, DOM object values, and any currently loaded script source code for the current page. It will also allow the user to place breakpoints on lines of script, as we do in Figure 6-9:

Figure 6-9

Attaching a breakpoint to JavaScript with Firebug

You can see that a breakpoint has been hit just before the call to the checkCredentials function. Lets step over this line, allow the client to call checkCredentials, and examine the return value (see Figure 6-10).

16

SPECIFIC SECURITY MISTAKES

Figure 6-10

Examining the return value from checkCredentials

Unfortunately, the username and password we provided do not appear to be valid. The value of the authenticated variable as returned from checkCredentials is false, and if we allow execution of this code to proceed as-is, the page will alert us that the credentials are invalid and then exit the purchaseSong function. However, as a hacker, this does us absolutely no good. Before we proceed, lets use Firebug to alter the value of authenticated from false to true, as we have done in Figure 6-11. By editing the value of the variable, we have modified the intended flow of the application. If we were to let the code continue execution at this point, it would assume (incorrectly) that we have a valid username and password, and proceed to retrieve the price of the selected song. However, while we have the black hat on, why should we stop at just bypassing authentication? We can use this exact same technique to modify the returned value of the song price, from $.99 to $.01 or free. Or, we could cut out the middleman and just use the Console window in Firebug to call the downloadSong function directly.

17

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

Figure 6-11

The attacker has modified the value of the authenticated variable from false to true

In this example, all of the required steps of the transactionchecking the users credentials, ensuring that she had enough money in her account, debiting the account and downloading the songshould have been encapsulated as one single public function. Instead of exposing all of these steps as individual methods in the server API, the programmers should have written a single purchaseSong method that would execute on the server and enforce the individual steps to be called in the correct order with the correct parameter values. The exposure of overly-granular server APIs is one of the most critical security issues facing Ajax applications today. It bears repeating: Never assume that client-side code will be executed the way you intendor even that it will be executed at all.

SESSION STATE STORED

IN JAVASCRIPT

The issue of inappropriately storing session state on the client is nothing new. One of the most infamous security vulnerabilities of all time is the client-side pricing vulnerability. Client-side pricing vulnerabilities occur when applications store item prices in a clientside state mechanism, such as a hidden form field or a cookie, rather than in server-side state. The problem with client-side state mechanisms is that they rely on the user to return the state to the server without tampering with it. Of course, trusting a user to hold data as tantalizing as item prices without tampering with it is like trusting a fiveyear-old to hold an ice cream cone without tasting it. When users are capable of deciding how much they want to pay for items, you can be certain that free is going to be a popular choice. While this issue is not new to Ajax, Ajax does add a new attack vector: state stored in client-side JavaScript variables. Remember the code from the online music store:
// get the price of the song var songPrice = getSongPrice(songId); // make sure the user has enough money in his account if (getAccountBalance(username) < songPrice) {

18

SPECIFIC SECURITY MISTAKES

alert(You do not have enough money in your account.); return; } // debit the users account debitAccount(username, songPrice);

By storing the song price in a client-side JavaScript variable, the application invites attackers to modify the value and pay whatever they like for their music. We touched on this concept earlier, in the context of making the server API too granular and allowing an attacker to manipulate the intended control flow. However, the problem of storing session state on the client is separate from the problem of having an API that is too-granular. For example, suppose that the server exposes an AddItem function to add an item to the shopping cart and a second function, CheckOut, to check out. This is a well-defined API in terms of granularity, but if the application relies on the client-side code to keep a running total of the shopping cart price, and that running total is passed to the CheckOut function, then the application is vulnerable to a client-side pricing attack.

SENSITIVE DATA REVEALED TO USERS


Programmers often hard code string values into their applications. This practice is usually frowned upon due to localization issuesfor example, it is harder to translate an application into Spanish or Japanese if there are English words and sentences hard coded throughout the source code. However, depending on the string values, there could be security implications as well. If the programmer has hard coded a database connection string or authentication credentials into the application, then anyone with access to the source code now has credentials to the corresponding database or secure area of the application. Programmers also frequently misuse sensitive strings by processing discount codes on the client. Lets say that the music store in our previous example wanted to reward its best customers by offering them a 50-percent-off discount. The music store emails these customers a special code that they can enter on the order form to receive the discount. In order to improve response time and save processing power on the Web server, the programmers implemented the discount logic in the client-side code rather than the serverside code.
<script type="text/javascript"> function processDiscountCode(discountCode) {

19

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

if (discountCode == "HALF-OFF-MUSIC") { // redirect request to the secret discount order page window.location = "SecretDiscountOrderForm.html"; } } </script>

The programmers must not have been expecting anyone to view the page source of the order form, because if they had, they would have realized that their secret discount code is plainly visible for anyone to find. Now everyone can have their music for half price. In some cases, the sensitive string doesnt even have to be a string. Some numeric values should be kept just as secret as connection strings or login credentials. Most e-commerce Web sites would not want a user to know the profit the company is making on each item in the catalog. Most companies would not want their employees salaries published in the employee directory on the company intranet. It is dangerous to hard code sensitive information even into server-side code, but in client-side code it is absolutely fatal. With just five seconds worth of effort, even the most unskilled n00b hacker can capture enough information to gain unauthorized access to sensitive areas and resources of your application. The ease with which this vulnerability can be exploited really highlights it as a critical danger. It is possible to extract hard coded values from desktop applications using disassembly tools like IDA Pro or .NET Reflector, or by attaching a debugger and stepping through the compiled code. This approach requires at least a modest level of time and ability, and, again, it only works for desktop applications. There is no guaranteed way to be able to extract data from serverside Web application code; this is usually only possible through some other configuration error, such as an overly-detailed error message or a publicly-accessible backup file. With client-side JavaScript, though, all the attacker needs to do is click the View Source option in his Web browser. From a hackers point of view, this is as easy as it gets.

COMMENTS AND DOCUMENTATION INCLUDED

IN

CLIENT-SIDE CODE

The dangers of using code comments in client code have already been discussed briefly in Chapter 5, but it is worth mentioning them again here, in the context of code transparency. Any code comments or documentation added to client-side code will be accessible by the end user, just like the rest of the source code. When a programmer explains the logic of a particularly complicated function in source documentation, she is not only making it easier for her colleagues to understand, but also her attackers.

20

SPECIFIC SECURITY MISTAKES

In general, you should minimize any practice that increases code transparency. On the other hand, it is important for programmers to document their code so that other people can maintain and extend it. The best solution is to allow (or force?) programmers to document their code appropriately during development, but not to deploy this code. Instead, the developers should make a copy with the documentation comments stripped out. This comment-less version of the code should be deployed to the production Web server. This approach is similar to the best practice concerning debug code. It is unreasonable and unproductive to prohibit programmers from creating debug versions of their applications, but these versions should never be deployed to a production environment. Instead, a mirrored version of the application, minus the debug information, is created for deployment. This is the perfect approach to follow for client-side code documentation as well. This approach does require vigilance from the developers. They must remember to never directly modify the production code, and to always create the comment-less copy before deploying the application. This may seem like a fragile process that is prone to human error. To a certain extent that is true, but we are caught between the rock of security vulnerabilities (documented code being visible to attackers) and the hard place of un-maintainable code (no documentation whatsoever). A good way to mitigate this risk is to write a tool (or purchase one from a third party) that automatically strips out code comments. Run this tool as part of your deployment process so that stripping comments out of production code is not forgotten.

S ECURITY N OTE Include comments and documentation in client-side code just as you would with server-side code, but never deploy this code. Instead, always create a comment-less mirrored version of the code to deploy.

DATA TRANSFORMATION PERFORMED

ON THE

CLIENT

Virtually every Web application has to handle the issue of transforming raw data into HTML. Any data retrieved from a database, XML document, binary fileor any other storage locationmust be formatted into HTML before it can be displayed to a user. In traditional Web applications, this transformation is performed on the server, along with all the other HTML that needs to be generated. However, Ajax applications are often designed in such a way that this data transformation is performed on the client instead of the server.

21

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

In some Ajax applications, the responses received from the partial update requests contain HTML ready to be inserted into the page DOM, and the client is not required to perform any data processing. Applications that use the ASP.NET AJAX UpdatePanel control work this way. In the majority of cases, though, the responses from the partial updates contain raw data in XML or JSON format that needs to be transformed into HTML before being inserted into the page DOM. There are many good reasons to design an Ajax application to work in this manner. Data transformation is computationally expensive. If we could get the client to do some of the heavy lifting of the application logic, we could improve the overall performance and scalability of the application by reducing the stress on the server. The downside to this approach is that performing data transformation on the client can greatly increase the impact of any code injection vulnerabilities such as SQL Injection and XPath Injection. Code injection attacks can be very tedious to perform. SQL Injection attacks, in particular, are notoriously frustrating. One of the goals of a typical SQL Injection attack is to break out of the table referenced by the query and retrieve data from other tables. For example, assume that a SQL query executed on the server is as follows:
SELECT * FROM [Customer] WHERE CustomerId = <user input>

An attacker will try to inject her own SQL into this query in order to select data from tables other than the Customer table, such as the OrderHistory table or the CreditCard table. The usual method used to accomplish this is to inject a UNION SELECT clause into the query statement (the injected code is shown in italics):
SELECT * FROM [Customer] WHERE CustomerId = x;

UNION SELECT * FROM [CreditCard]

The problem with this is that the results of UNION SELECT clauses must have exactly the same number and type of columns as the results of the original SELECT statement. The command shown in the example above will fail unless the Customer and CreditCard tables have identical data schemas. UNION SELECT SQL Injection attacks also rely heavily on verbose error messages being returned from the server. If the application developers have taken the proper precautions to prevent this, then the attacker is forced to attempt blind SQL Injection attacks (covered in depth in Chapter 3), which are even more tedious than UNION SELECTs. However, when the query results are transformed into HTML on the client instead of the server, neither of these slow, inefficient techniques is necessary. A simple appended

22

SPECIFIC SECURITY MISTAKES

SELECT

clause is all that is required to extract all the data from the database. Consider our previous SQL query example:

SELECT * FROM [Customer] WHERE CustomerId = <user input>

If we pass a valid value like gabriel for the CustomerId, the server will return an XML fragment that would then be parsed and inserted into the page DOM.
<data> <customer> <customerid>gabriel</customerid> <lastname>Krahulik</lastname> <firstname>Mike</firstname> <phone>707-555-2745</phone> </customer> </data>

Now, lets try to SQL inject the database to retrieve the CreditCard table data simply by injecting a SELECT clause (the injected code is shown in italics).
SELECT * FROM [Customer] WHERE CustomerId = x;

SELECT * FROM [CreditCard]

If the results of this query are directly serialized and returned to the client, it is likely that the results will contain the data from the injected SELECT clause.
<data> <creditcard> <lastname>Holkins</lastname> <firstname>Jerry</firstname> <ccnumber>1234567812345678</ccnumber> <expirationDate>09-07-2010</expirationDate> </creditcard> <creditcard> </data>

At this point, the client-side logic that displays the returned data may fail because the data is not in the expected format. However, this is irrelevant because the attacker has

23

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

already won. Even if the stolen data is not displayed in the page, it was included with the servers response, and any competent hacker will be using a local proxy or packet sniffing tool so that he can examine the raw contents of the HTTP messages being exchanged. Using this simplified SQL Injection technique, an attacker can extract out the entire contents of the back end database with just a few simple requests. A hack that previously would require thousands of requests over a matter of hours or days might now take only a few seconds. This not only makes the hackers job easier, it also improves his chances of success because there is less likelihood that he will be caught by an intrusion detection system. Making 20 requests to the system is much less suspicious than making 20,000 requests to the system. This simplified code injection technique is by no means limited to use with SQL Injection. If the server code is using an XPath query to retrieve data from an XML document, it may be possible for an attacker to inject his own malicious XPath clause into the query. Consider the following XPath query:
/Customer[CustomerId = <user input>]

An attacker could XPath inject this query as follows (the injected code is shown in italics):
/Customer[CustomerId = x] | /*

The | character is the equivalent of a SQL JOIN statement in XPath, and the /* clause instructs the query to return all of the data in the root node of the XML document tree. The data returned from this query will be all customers with a customer ID of x (probably an empty list) combined with the complete document. With a single request, the attacker has stolen the complete contents of the back end XML. While the injectable query code (whether SQL or XPath) is the main culprit in this vulnerability, the fact that the raw query results are being returned to the client is definitely a contributing factor. This design antipattern is typically only found in Ajax applications and occasionally in Web services. The reason for this is that Web applications (Ajax or otherwise) are rarely intended to display the results of arbitrary user queries. Queries are usually meant to return a specific, predetermined set of data to be displayed or acted on. In our earlier example, the SQL query was intended to return the ID, first name, last name, and phone number of the given customer. In traditional Web applications, these values are typically retrieved by element or column name from the query result set and written into the page HTML. Any attempt to inject a simplified ;SELECT attack clause into a traditional Web application query may succeed; but because

24

SPECIFIC SECURITY MISTAKES

the raw results are never returned to the client and the server simply discards any unexpected values, there is no way for the attacker to exploit the vulnerability. This is illustrated in Figure 6-12.
SELECT*FROM CreditCard SELECT*FROM Customer SELECT* FROM CreditCard

Returned data
Customer User Server Filter data

Returned data
Customer Database CreditCard

Figure 6-12 A traditional Web application using server-side data transformation will not return the attackers desired data.

Compare these results with the results of an injection attack against an Ajax application that performs client-side data transformation (as shown in Figure 6-13). You will see that it is much easier for an attacker to extract data from the Ajax application.
SELECT*FROM CreditCard SELECT*FROM Customer SELECT* FROM CreditCard

Returned data
Customer User Return all data Server

Selected data
Customer Database

CreditCard

CreditCard

Figure 6-13

An Ajax application using client-side data transformation does return the attackers

desired data.

Common implementation examples of this antipattern include:

Use of the FOR XML clause in Microsoft SQL Server Returning .NET System.Data.DataSet objects to the client Addressing query result elements by numeric index rather than name Returning raw XPath/XQuery results

The solution to this problem is to implement a query output validation routine. Just as we validate all input to the query to ensure that it matches a predetermined format, we

25

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

should also validate all output from the query to ensure that only the desired data elements are being returned to the client. It is important to note that the choice of XML as the message format is irrelevant to the vulnerability. Whether we choose XML, JSON, comma-separated values, or any other format to send data to the client, the vulnerability can still be exploited unless we validate both the incoming query parameters and the outgoing results.

SECURITY THROUGH OBSCURITY


Admittedly, the root problem in all of the specific design and implementation mistakes weve mentioned is not the increased transparency caused by Ajax. In MyLocalWeatherForecast.com, the real problem was the lack of proper authorization on the server. The programmers assumed that because the only pages calling the administrative functions already required authorization, then no further authorization was necessary. If they had implemented additional authorization checking in the server code, then the attacks would not have been successful. While the transparency of the client code did not cause the vulnerability, it did contribute to the vulnerability by advertising the existence of the functionality. Similarly, it does an attacker little good to learn the data types of the server API method parameters if those parameters are properly validated on the server. However, the increased transparency of the application provides an attacker with more information about how your application operates and makes it more likely that any mistakes or vulnerabilities in the validation code will be found and exploited. It may sound as if were advocating an approach of security through obscurity, but in fact this is the complete opposite of the truth. It is generally a poor idea to assume that if your application is difficult to understand or reverse-engineer, then it will be safe from attack. The biggest problem with this approach is that it relies on the attackers lack of persistence in carrying out an attack. There is no roadblock that obscurity can throw up against an attacker that cannot be overcome with enough time and patience. Some roadblocks are bigger than others; for example, 2048-bit asymmetric key encryption is going to present quite a challenge to a would-be hacker. Still, with enough time and patience (and cleverness) the problems this encryption method presents are not insurmountable. The attacker may decide that the payout is worth the effort, or he may just see the defense as a challenge and attack the problem that much harder. That being said, while its a bad idea to rely on security through obscurity, a little extra obscurity never hurts. Obscuring application logic raises the bar for an attacker, possibly stopping those without the skills or the patience to de-obfuscate the code. It is best to look at obscurity as one component of a complete defense and not a defense in and of

26

SECURITY THROUGH OBSCURITY

itself. Banks dont advertise the routes and schedules that their armored cars take, but this secrecy is not the only thing keeping the burglars out: The banks also have steel vaults and armed guards to protect the money. Take this approach to securing your Ajax applications. Some advertisement of the application logic is necessary due to the requirements of Ajax, but always attempt to minimize it, and keep some (virtual) vaults and guards around in case someone figures it out.

OBFUSCATION
Code obfuscation is a good example of the tactic of obscuring application logic. Obfuscation is a method of modifying source code in such a way that it executes in exactly the same way, but is much less readable to a human user. JavaScript code cant be encrypted because the browser wouldnt know how to interpret it. The best that can be done to protect client-side script code is to obfuscate it. For example,
alert("Welcome to JavaScript!");

might be changed to this:


a = "lcome to J"; b = "al"; c = "avaScript!\")"; d = "ert(\"We"; eval(b + d + a + c);

These two blocks of JavaScript are functionally identical, but the second one is much more difficult to read. Substituting some Unicode escape characters into the string values makes it even harder:
a = "\u006c\u0063\u006fme t\u006f J"; b = "\u0061\u006c"; c = "\u0061v\u0061Sc\u0072ipt\u0021\")"; d = "e\u0072t(\"We"; eval(b + d + a + c);

There are practically an endless number of techniques that can be used to obfuscate JavaScript, several of which are described in the Validating JavaScript Source Code section of Chapter 4, Ajax Attack Surface. In addition, there are some commercial tools

27

CHAPTER 6

TRANSPARENCY

IN

AJAX APPLICATIONS

available that will automate the obfuscation process and make the final code much more difficult to read than the samples given here. HTML Guardian by ProtWare is a good example. Its always a good idea to obfuscate sensitive code, but keep in mind that obfuscation is not the same as encryption. An attacker will be able to reverse engineer the original source code given enough time and determination. Obfuscating code is a lot like tearing up a bank statementit doesnt make the statement impossible to read, it just makes it harder by requiring the reader to reassemble it first.

S ECURITY R ECOMMENDATION Dont Dont confuse obfuscation with encryption. If an attacker really wants to read your obfuscated code, he will. Do Do obfuscate important application logic code. Often this simple step is enough to deter the script kiddie or casual hacker who doesnt have the patience or the skills necessary to recreate the original. However, always remember that everything that is sent to the client, even obfuscated code, is readable.

CONCLUSIONS
In terms of security, the increased transparency of Ajax applications is probably the most significant difference between Ajax and traditional Web applications. Much of traditional Web application security relies on two properties of server-side codenamely, that users cant see it, and that users cant change it. Neither of these properties holds true for client-side Ajax code. Any code downloaded to a users machine can be viewed by the user. The application programmer can make this task more difficult; but in the end, a dedicated attacker will always be able to read and analyze the script executing on her machine. Furthermore, she can also change the script to alter the flow of the application. Prices can be changed, authentication can be bypassed, and administrative functions can be called by unauthorized users. The solution is to keep as much business logic as possible on the server. Only server-side code is under the control of the developers client-side code is under the control of attackers.

28

I S B N : 0 -13 -2 242 0 6 - 0

B U Y TH E b OO K TO DAY

ENTERPRISE AJAX
Strategies for Building High Performance Web Applications

Dave Johnson, Alexei White, and Andre Charland

Upper Saddle River, NJ Boston Indianapolis San Francisco New York Toronto Montreal London Munich Paris Madrid Cape Town Sydney Tokyo Singapore Mexico City

CHAPTER 4

AJAX COMPONENTS
In this chapter, after examining several patterns, we look at how they apply to actually building a user interface. You learn how to encapsulate AJAX functionality into both imperative, as well as declarative, components. The use of declarative components is increasingly important because various new declarative technologies are created, such as Scaling Vector Graphics (SVG), XML Binding Language (XBL), and Macromedia XML (MXML). The encapsulation of user-interface functionality is a critically important aspect of enterprise AJAX development because it not only facilitates code re-use, but it also removes much of the need for addressing the individual quirks of multiple browsersa critical step toward rapidly developing high-quality, rich AJAX applications. We can build an application using conventional classes, some aspectoriented programming, the DOM, and DOM Events. Until now, our code has, for the most part, been cobbled together using our MVC architecture. The next step is to refractor our Customer list application into something more modular and componentized so that we can re-use the code across an application, or even throughout the enterprise. By the end of this chapter, we will have converted our customer listing AJAX application into a full-fledged declarative AJAX component. We also look at a few of the available client-side AJAX frameworks.

Imperative Components
Now that you have a clear idea of how to get your JavaScript running when a web page loads, you can look at how to actually use JavaScript, the DOM, and CSS to make an AJAX component. If you have any experience in server-side programming, you are probably familiar with writing code in an imperative manner. Imperative programming is what most developers are familiar with and is a sequence of commands that the computer is to execute in the specified order. We can easily instantiate a component with 135

136

Chapter 4

AJAX Components

JavaScript by creating a new object and, as is often the case, subsequently specify an HTML element through which the View can be renderedthis would be an imperative component implemented through JavaScript. Imperative coding is much like making a ham-and-cheese sandwich. To end up with a ham-and-cheese sandwich, you need to follow certain steps: 1. 2. 3. 4. 5. Get the bread. Put mayo and mustard on the bread. Put the ham and cheese on the bread. Close the sandwich. Enjoy!

If you try to close the sandwich at a different stage or put the ham and cheese on the bread before the mayo, you might end up with a mess! This equally applies to writing JavaScript or AJAX in an imperative manner. A good example of an imperative JavaScript component, that some of you might have used, is the popular Google Map component that we look at how to work with through JavaScript. People generally integrate a Google Map with their own application, building a so called mashup, all using imperative JavaScript code. Although it might seem out of place, it can be useful to include public AJAX applications such as Google Maps in an enterprise setting. Google Maps are extremely useful for visualization of geographic data such as shipment tracking, fleet tracking, or locating customers. At any rate, to begin with, as with any JavaScript component, you need to ensure that the JavaScript libraries provided by Google are included in the web page. In the case of Google Maps, the JavaScript code can be included by using a single <script> element <script> element; Google Maps such as the following:
<html> <head> <script src="http://maps.google.com/maps? file=api&v=2&key=#INSERT_KEY_HERE#" type="text/javascript"></script> </head> <body> <div id="map" style="width: 370px; height: 380px"></div> </body> </html>

Imperative Components

137

To use the Google Maps service, as with many other publicly available AJAX components or web-based data sources, you need to register with Google to get an API key that is passed to the Google service as a querystring parameter in the script location. Having loaded the script from the Google server and using at least one of the bootstrapping techniques from the previous section, you might create a Google Map like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"> <head> <style type="text/css"> v\:* {behavior:url(#default#VML);} </style> <script src="http://maps.google.com/maps?file=api&v=2&key=#INSERT_KEY_ HERE#" type="text/javascript"></script> <script type="text/javascript"> var gmap = {}; function gmap.init() { var map = new GMap2(document.getElementById("map")); // Center on Vancouver map.setCenter(new GLatLng(49.290327, -123.11348), 12); } // Attach the init function to window.onload event entAJAX.attachAfter(window, "onload", gmap, "init"); </script> </head> <body> <div id="map" style="width: 370px; height: 380px"></div> </body> </html>

There is a considerable amount of overhead here, such as the XHTML doctype and the reference to the Vector Markup Language (VML) behavior that is used for Internet Explorer; the important parts are the inclusion of the external Google Maps JavaScript file and the init() function that

138

Chapter 4

AJAX Components

creates a new map and sets the map center to be Vancouver. The map is placed inside of the DOM element that has an id value of map. When an instance of the GMap2 class has been created, you can access its various properties and methods through the exposed JavaScript API. Here, we show how a GPolyLine object can be added to the map using an array of GLatLng points:
var polyline = new GPolyline([ new GLatLng(49.265788, -123.069877), new GLatLng(49.276988, -123.069534), new GLatLng(49.276988, -123.099746), new GLatLng(49.278108, -123.112106), new GLatLng(49.2949043, -123.136825)], "#ff0000", 10); map.addOverlay(polyline);

The result of imperatively creating this Google Map, as shown in Figure 4.1, is an impressive and highly interactive map centered on Vancouver with a route through the city that looks something like this:

Figure 4.1 Path Displayed on a Google Map Using the Google Map API

Declarative Components

139

The type of JavaScript code required to create a Google Map in a web application is exactly the sort of code you might expect to see in any common user-interface development language. In fact, looking at the code, you might think that it is written in a server-side language. Although today, imperative coding might be the norm; going forward, AJAX development will become increasingly declarative. This is certainly reflected in the fact that companies such as Microsoft and Adobe are pursuing those avenues with XML-Script and Spry, respectivelynot to mention the next generation technologies from both of those companies again in WPF/E and Flex, which are both based on XML declarative programming models. Google Maps is a quintessential imperative AJAX component; however, to get a good grasp of declarative programming, lets look at how to convert a Google Map to be a declarative component.

Declarative Components
Although defining components in an imperative manner can be useful, it is also increasingly common to see components defined using a declarative approach. You probably already know at least one declarative language; HTML and XSLT are two common examples of declarative languages. When using declarative components, the developer doesnt need to worry about how things are achieved behind the scenes but instead only needs to worry about declarative structure; for example, in HTML, the web browser parses and interprets the tags based on some predefined set of rules. The result of this is that when the HTML parser finds text surrounded in <em> tags, it presents that text with emphasis. Exactly how the text is emphasized by default is left up to the web browser, although that can, of course, be overridden by the developer using CSS. Because the markup or declaration specifies what a component does rather than how it works is the biggest advantage to declarative programming. When discussing imperative coding, you learned that making a hamand-cheese sandwich ended up being a bit of a pain to achieve the right outcome. On the other hand, a ham-and-cheese sandwich created using a declarative approach would go something more like this: 1. Ham and cheese sandwich please. 2. Enjoy!

140

Chapter 4

AJAX Components

Rather than having to specify each of the steps involved in making the sandwich, it is more like going to your local caf and ordering the sandwich from the waiter. It is certainly fewer steps and probably a lot more convenient to make the sandwich declaratively rather than imperatively; however, there are some drawbacks. The most apparent drawback here is that if you arent careful, the waiter might bring you a ham-and-cheese sandwich without any mustard! You might be familiar with declarative programming from any one of the gamut of server-side web application frameworks employing a declarative approach, such as JavaServer Faces, JSP, and ASP.NET. In these languages, you can define a part of the page using a declarative syntax that is then processed on the server and produce standard HTML that is delivered to the client like any other web page.

Server-Side Declarative Programming


In ASP.NET, you can define a web page with a declarative DataGrid control like this:
<asp:DataGrid id="ItemsGrid" BorderColor="black" BorderWidth="1" CellPadding="3" AutoGenerateColumns="true" runat="server"> </asp:DataGrid>

What happens to this declaration is that the .NET framework loads the ASPX web page containing the declaration, and the declaration is processed and replaced with regular HTML by the server, which then gets streamed up to the client as though it were plain HTML page. Of course you can see that there is certainly more to the story than just that simple declaration because there is no mention of what data is to be rendered in the DataGrid. Although these various server-side technologies do provide a nice declarative interface, they still require a little bit of code to hook everything together. Behind the scenes of the ASPX HTML page is a code page that might have some C# code such as this to connect the DataGrid to a database:
// Define the DataGrid protected System.Web.UI.WebControls.DataGrid ItemGrid; private void Page_Load(object sender, System.EventArgs e)

Declarative Components

141

{ ItemGrid.DataSource = myDataSet; ItemGrid.DataBind(); }

By combing the declarative and imperative approaches, developers get the best of both worlds, enabling them to develop a simple application rather quickly, still having the control to tweak all aspects of the application components. There are many advantages to taking a declarative approach to building applications. The most obvious advantage of markup is that it is more designable than code in that it enables far better tool support. ASP.NET or JavaServer Face components in Visual Studio or JavaStudio Creator are good examples of this where you can drag components into a web page during application design and visually configure without writing code. The fact that a declaration is just a snippet of XML means that XML Schema can be used to ensure that a declaration adheres to an expected XML structure. Validating against a rigid XML schema makes declarative components much less error prone than the pure JavaScript counterparts. Writing declarations in a web editor such as Eclipse or Visual Studio can also be made easier by using autocomplete features (for example IntelliSense for Visual Studio) that ensure the declaration adheres to the XML schema as the declaration is being written. In fact, at some point, things can become even more simplified because a DataGrid in one declarative framework, like Adobes MXML language, is little more than an XSLT transformation away from a DataGrid in some other language like XFormsthus, achieving the same functionality across platforms without changing and recompiling a single line of code. Of course, with some effort, this can be said of almost any programming language; however, declarative programming does have the advantage that the order in which statements are declared has no impact on the operation of the component, and declarations are XML-based and, therefore, readily machine readable. Although a declaration can get a developer most of the way to building a great application, there is always that last little bit that requires more fine control to customize a component in specific ways. In these instances, you can still fall back on the programming language that the declarative framework is build on, be it Java, C#, or JavaScript.

142

Chapter 4

AJAX Components

Declarative Google Map


A declaration is just an abstraction layered over the top of imperative code. Elements in a declaration roughly map to objects and attributes to fields or properties on those objects. Although a declaration does not specify anything about the methods of an object, and it shouldnt, it can express everything about the state of an object or, perhaps more familiar to you, the serialized form of an object. In the case of our imperative Google Maps example, we create, set up, and render a Google Map entirely through error prone and uncompiled JavaScript resulting in a map that has a certain zoom level and is centered on some lat/long coordinates. Ideally, we can instead take an XML description of the map containing all the information about the mapzoom level, center coordinates, and so onand instantiate a map based on that state information stored in the XML. So, rather than defining our Google map with JavaScript, you can use a custom XHTML declaration that describes the state of a serialized map, which gets deserialized (by some code that you can write) resulting in a map as though you had explicitly written the JavaScript code. A Google Map declaration based on the imperative code we wrote previously might look something like this:
<g:map id="map" width="370px" height="380px" smallmapcontrol="true" maptypecontrol="true"> <g:center zoom="14"> <g:point lat="49.2853" lng="-123.11348"></g:point> </g:center> <g:polyline color="#FF0000" size="10"> <g:point lat="49.265788" lng="-123.069877"></g:point> <g:point lat="49.276988" lng="-123.069534"></g:point> <g:point lat="49.276988" lng="-123.099746"></g:point> <g:point lat="49.278108" lng="-123.112106"></g:point> <g:point lat="49.294904" lng="-123.136825"></g:point> </g:polyline> </g:map>

The parallels between this declaration and the imperative code are clearalmost every line in the declaration can be identified as one of the JavaScript lines of code. The biggest difference is that, as we have discussed, the declaration specifies only how the map should be displayed independent of any programming language and in an industry-standard, easily machine-readable, and valid (according to an XML Schema) format.

Declarative Components

143

The actual code used to convert that to an instance of a Google Map is left up to the declaration processor, which again, can be implemented in any language or platformin our case, we stick with the web browser and JavaScript. Furthermore, the dependence on order of statements in imperative codingthat you must create the map object before setting properties on itis masked by the nested structure of the XHTML declaration, making it unnecessary for a developer to understand any dependencies on the order in which code is executed. However, they must understand the XML schema for the declaration. Lets take a closer look at what we have defined here for our map declaration. First, we defined the root of our declaration using a DOM node with the special name of <g:map> <g:map> DOM node where the g prefix is used to specify a special namespace. This makes the HTML parser recognize those tags that dont belong to the regular HTML specification. When the component is loaded from the declaration, we want it to result in a Google Map created in place of the declaration, and that map will have the specified dimensions, zoom level, and center point. Similarly, it will result in a polyline drawn on the map with the given color and start and end points. The only trick is that we need to write the JavaScript code to go from the declaration to an instance of a map! Because the web browser has no knowledge of our custom XHTMLbased declaration, it does not have any built-in code to find and create our component based on the declaration. To go from our component declaration to an instance of an AJAX component, we need to use almost all the technologies that we have learned about so far. To start with, we need to bootstrap using one of the techniques discussed in Chapter 3, AJAX in the Web Brower,the exact same as we would need to do to with an imperative component. Our Google Map sample page now becomes the following:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:g="http://www.enterpriseAJAX.com/gmap"> <head> <link rel="stylesheet" href="gmaps.css" type="text/css"></link> <script src="http://maps.google.com/maps?file=api&v=2&key=#INSERT_KEY_ HERE#" type="text/javascript"></script>

144

Chapter 4

AJAX Components

<script type="text/javascript" src="entajax.toolkit.js"></script> <script type="text/javascript" src="gmaps.js"></script> </head> <body> <g:map id="map" width="370px" height="380px" smallmapcontrol="true" maptypecontrol="true"> <g:center zoom="14"> <g:point lat="49.2853" lng="-123.11348"></g:point> </g:center> <g:polyline color="#FF0000" size="10"> <g:point lat="49.265788" lng="-123.069877"></g:point> <g:point lat="49.276988" lng="-123.069534"></g:point> <g:point lat="49.276988" lng="-123.099746"></g:point> <g:point lat="49.278108" lng="-123.112106"></g:point> <g:point lat="49.294904" lng="-123.136825"></g:point> </g:polyline> </g:map> </body> </html>

There is now no sign of any JavaScript on the web page, but we added two additional external JavaScript files that are responsible for parsing the declaration, moved the special CSS into an external file, and added the declaration itself. This is the sort of page that a designer or someone unfamiliar with JavaScript could write. The included entajax.toolkit.js file contains all the helper classes and functions that we need to make this work on Firefox, Internet Explorer, and Safari. In gmaps.js is where all the magic happens. The contents of gmaps.js looks like this:
entAjax.initComponents = function() { // Iterate over all pre-defined elements for (var tag in entAjax.elements) { // Get the all the <G:*> elements in the DOM var components = entAjax.html.getElementsByTagNameNS(tag, g); for (var i=0; i<components.length; i++) {

Declarative Components

145

// A custom element is only initialized if it is a root node if (entAjax.isRootNode(components[i])) { // Call the defined method that handles such as component entAjax.elements[tag].method(components[i]); } } } } entAjax.attachAfter(window, "onunload", entAjax, "initComponents");

The initComponents() method depends on a few things. First, to facilitate a flexible and extensible approach to building JavaScript components from XHTML, we use a global hash where the keys are the expected HTML element names and the values contain additional metadata about how to deserialize that XHTML element into a JavaScript. This approach is analogous to a more general technique that can deserialize a component based on the XHTML schema. For a small, representative subset of the available parameters that can be used to create a Google Map, the entAjax.elements hash might look something like this:
entAjax.elements = { "map":{"method":entAjax.createGMap,"styles":["width","height"] }, "smallmapcontrol":{"method":entAjax.createSmallMapControl}, "maptypecontrol":{"method":entAjax.createMapTypeControl}, "polyline":{"method":entAjax.createPolyline}, "center":{"method":entAjax.centerMap}};

We have defined five keys in the entAjax.elements hash that are map, smallmapcontrol, maptypecontrol, polyline, and center. For each of these keys, which relate to expected DOM node names, we define an object with a method field and a possible styles field. The method refers to the JavaScript function used to deserialize the DOM node with the specified node name, and the styles is an array that we use

146

Chapter 4

AJAX Components

to map possible attributes from the <g:map> element to CSS style valuesin this case, we want to transform <g:map width="370px" height="380px"> to an HTML element that looks like <div id= "map-1" style="width:370;height:380px;">. We used the entAjax.getElementsByTagNameNS function to obtain references to the custom XHTML elements rather than the native DOM getElementsByTagNameNS method. The reason for this is that Internet Explorer does not support element selection by namespace, and other browsers such Firefox, Safari, and Opera use it only when the web page is served as XHTML, meaning that it must have content-type application/xhtml+xml set in the HTTP header on the server. Internet Explorer has one more quirk in that it completely ignores the element namespace and selects elements based entirely on the local name, such as map. On the other hand, other browsers accept a fully qualified tag name such as g:map when not operating as XHTML. The entAjax.get ElementsByTagNameNS function effectively hides these browser nuances. After getting a list of all the custom tags in the web page, we then use the tag constructor definitions in the entAjax.elements hash to find the method that we have written to instantiate that element into the equivalent JavaScript object.
entAjax.elements[tag].method(components[i]);

We pass one argument to the root tag constructors, which is the declaration element from which the entire component can then be built. Each of the methods in the entAjax.elements hash can be thought of as factories according to the Factory pattern. In the case of the <g:map> XHTML element, the createGMap function is called. The createGMap function is a custom function used to create an instance of the GMap2 class as well as set up all the child controls and relevant properties:
entAjax.createGMap = function(declaration) { var container = document.createElement('div'); entAjax.dom.insertAdjacentElement("afterEnd", declaration, container); // Move any declaration attributes to the Map style parseStyle(entAjax.elements["map"].styles, declaration, container); var gmap = new GMap2(container);

Declarative Components

147

// Iterate over attributes on DOM node forAttributes(declaration, function(attr) { container.setAttribute(attr.nodeName, attr.nodeValue); if (entAjax.elements[attr.nodeName] != null) entAjax.elements[attr.nodeName].method(gmap, attr); }); // Iterate over child DOM nodes forChildNodes(declaration, function(elem) { entAjax.elements[formatName(elem.nodeName)].method(gmap, elem); }); }

For each <g:map> element, we create a standard <div> element <div> elements to which the map will be attached. This will generally be the case that a component needs to be attached to a standard HTML <div> element and then create an instance of the GMap2 class with the newly created <div> element as the single constructor argument. Two general operations need to be performed for declaration parsing; first, all attributes on the declaration node must be processed, and second, all child elements of the declaration node need to be processed. Due to the way that the GMap2 component was designed, we also need to copy some custom style information from the declaration node, such as the width and height, onto the <div> container element. Many of these special cases can be generalized in a component framework but are much less elegant when wrapping declarative functionality around a JavaScript component built without declarative functionality in mind.

Alternative Approaches
Although we used custom XHTML for our declaration, it is also possible to use other techniques for configuring your components. The most popular alternative to configuring components with an XML-based declaration is to use a simple JavaScript object. For our map example, the following would be a likely format for a map configuration:
var configuration = {"map":{ "center":{ "zoom":10,"point":{"lat":23,"lng":-122} },

148

Chapter 4

AJAX Components

"polyline":{ "color":"#FF0000","size":10,"points":[ {"lat":49.265788,"lng":-123.069877}, {"lat":49.276988,"lng":-123.069534} ]}}}

This configuration can then be used as the single argument passed to the map factory and would result in a map just the same as the XHTML declarative approach we outlined. Using a JavaScript object such as that is the way that Yahoos AJAX user-interface components accept configurations. Another way to configure an AJAX component, although it is currently fairly uncommon, is to use CSS properties. Using CSS to configure AJAX components is particularly effective because CSS can be linked through external files using the HTML <link> element, and the technology is familiar to most web designers today. However, CSS does have considerably less expressiveness when compared to either a JavaScript object or an XHTML declaration, and some dynamic CSS functionality is not available in browsers such as Safari. Chapter 2, AJAX Building Blocks, covered how to dynamically access and manipulate stylesheet rules through the DOM API. Looking at the Google Map example and seeing how to convert an existing component to a declaration should have been helpful in identifying not only how a declarative approach can make AJAX development easier, but how we can use it to build rich Internet applications. Having gone through this exercise with a Google Map, there might be a few questions in your head now such as how we can deal with events, data binding, or data templating in a declarative manner. We look at of those issues and more in the next section.

Custom Declarative Component


Now that you have had a chance to consider how a declarative approach might work using a well-known AJAX component as an example, you will build your own custom AJAX declarative component. Lets go through the steps of building an AJAX DataGrid control, which is a useful piece of user interface functionality and is used to iterate over a list of JavaScript objects,

Custom Declarative Components

149

such as a list of Product objects, and render each item as a row in a table, applying a common style or formatting to each item. Many server frameworks such as JSF and ASP.NET have DataGrid components that can be attached to a list of objects or a database query and display those objects or records in the user interface. There are also fully client-side alternatives that can connect to the server using AJAX. For now, we keep it simple and look at how to build a declarative AJAX user interface component while using OOP design patterns and applying MVC principles. The first type of declarative component we look at is exceedingly simplein fact, so simple that it is entirely based on HTML markup and CSS. In this case, the output of the component is a product of explicitly stating all the columns and data for a table of product information. Although this might seem like a strange place to start, HTML is actually the definitive declarative markup. Each element in the declaration has a class attribute that connects the HTML to the styling information contained in the associated CSS, and each element has an id attribute that is used for both styling and for making the elements uniquely addressable from JavaScript. Markup for an HTML DataGrid might look like this:
<table id="myGridList" class="gridlist"> <thead> <tr id="header" class="header-group"> <td id="header-0" class="header header-0">Product</td> <td id="header-1" class="header header-1">Price</td> </tr> </thead> <tbody> <tr id="row-0" class="row"> <td id="cell-0_0" class="column column-0">Acme Widget</td> <td id="cell-0_1" class="column column-1">$19.99</td> </tr> <tr id="row-1" class="row row-alt"> <td id="cell-1_0" class="column column-0">Acme Box</td> <td id="cell-1_1" class="column column-1">$9.99</td> </tr> <tr id="row-2" class="row"> <td id="cell-2_0" class="column column-0">Acme Anvil</td> <td id="cell-2_1" class="column column-1">$14.99</td>

150

Chapter 4

AJAX Components

</tr> </tbody> <tfoot> <tr id="footer" class="footer-group"> <td id="footer-0" class="footer footer-0">Total</td> <td id="footer-1" class="footer footer-1">$43.97</td> </tr> <tfoot> </table>

We use HTML <table> elements (see Figure 4.2) as opposed to the <div> elements for accessibility reasonsmore on this in Chapter 7, Web Services and Security. As you can tell from the HTML declaration itself, the result is a basic layout of each product item, column headers, and footers. There is nothing magical about this however, this is an important step in designing a declarative component because it gives you a clear idea of the HTML structure that you want to achieve.

class SimpleGrid

class Component attributes: Array element: HTMLElement elements: Array id: char renderTemplates: Object Component class SimpleGrid + * 1 + + + columns: SimpleGridColumn (Array) cssClass: char cssStyle: char dataSource: DataModel footerPreProcessor: Processor headerPreProcessor: Processor itemPreProcessor: Processor template: char dispose() : void render() : void renderReady() : void setDataSource(DataModel) : void

+ deserialize() : void

class SimpleGridColumn cssClass: char cssStyle: char footer: ColumnFooter header: ColumnHeader item: ColumnItem width: int

Figure 4.2 Simple HTML Table Displays a List of Products with Names and Prices

Custom Declarative Components

151

The CSS classes specified in the HTML provide the styling information to make the header and footer contents bold, make the data background color alternate, and specify the grid dimensions. All the styling information for your component or application needs to be powered by CSS, which is no different for an AJAX application from a traditional postback HTML application. The contents of the CSS file for the list of previous products looks like this:
.theme #myGridList { width:200px; border:1px solid black; } .theme .columnheader-group, .theme .columnfooter-group { height:20px; font-weight:bold; border-bottom:1px solid black; } .theme .columnheader, .theme .column, .theme .columnfooter { float:left; overflow:hidden; } .theme .columnheader-0, .theme .column-0, .theme .columnfooter-0 { width:100px; } .theme .columnheader-1, .theme .column-1, .theme .columnfooter-1 { width:50px; } .theme .row, .theme .column { height:18px; } .theme .row-alt { background-color: #E5E6C6; }

Notice a few things here. First, we used a descendent selector to differentiate the given styles based on the theme class; the styles listed will be applied only to elements that have an ancestor element with the theme class. Something else that influences design decisions significantly is that

152

Chapter 4

AJAX Components

in the case of a DataGrid, and most any databound component for that matter, we need to define a custom CSS rule for each of the user-specified columns in the DataGrid and for each of the regions of a column (that is, the header, data, and footer). In the extreme, we could even specify CSS rules for each row of data, as might be the case if we were building a spreadsheet component. This is where dynamic creation of styles can come in handy, and browsers that dont support dynamic style functionality, such as Safari, start to become liabilities to your application performance and ease of development. The alternative to using CSS classes for specifying the column widths is to set the style attribute on the column directly. Although you now have a nice-looking DataGrid populated with data, building the component explicitly in HTML is not helpful because the data and structure are all combined making it difficult to change any one aspect of the data or presentation. However, there is a reason we started by looking at a static HTML table. By laying out the HTML, it helps to get a better grasp of how to merge the data, structure, and styling in the most efficient manner both from the point of view of HTML footprint and computational complexity. To ensure that the HTML footprint is small, we used as few HTML elements as possibleonly those necessary for laying out the dataand have used both ID and class-based CSS selectors to apply all styling to the data. We have taken advantage of the fact that we can apply a single style to multiple elements; in particular, we use this feature to set the width of the column header, data, and footer all in one CSS rule such as the following:
.columnheader-0, .column-0, .columnfooter-0 {width:100px;}

Behavior Component
Another reason that we started by looking at hard-coded HTML to make an AJAX component is that we can make a good start by adding AJAX to our hard-coded HTML using a behavioral approach. This can be a good approach if things such as graceful failure are important because it can easily fall back on the standard HTML markup in cases when users have web browsers that either dont have JavaScript enabled or dont support certain core AJAX functionality such as the XHR object. These are becoming more and more unlikely, particularly in the enterprise where computer software is generally centrally configured and managed. Similarly, behavioral components enable you to incrementally add AJAX features to ren-

Custom Declarative Components

153

dered HTML where the HTML might have come from some existing server-side framework, enhancing the value of your existing web application assets. The Microsoft AJAX Framework (formerly known as Atlas) has a considerable focus on behavioral components. For example, rather than creating an autocomplete component, the Microsoft AJAX Framework has an autocomplete behavior, quintessential AJAX, that can be applied to any existing component such as a standard HTML <input> element. In this case, much like a dynamic <select> element, it adds the ability to allow users to dynamically choose words from a database as they type in the <input> control. For our DataGrid component, adding some grid-like behavior to the standard HTML might entail enabling the end user to edit or sort data in the grid. Defining behavioral components is often done declaratively by extending the default HTML markup and setting some metadata on a standard HTML element. For the most part, this metadata consists of a CSS class name that generally does not have any actual style information associated with it. To instantiate a behavioral component, the bootstrapper scours the DOM to find elements with recognizable metadatabe it a CSS class name or otherwise. When an element with known metadata is discovered, the standard component instantiation commences. Markup for a sortable HTML table can have an additional class, such as sortable, which would look like this:
<table id="mySortableTable" class="gridlist sortable"></table>

The code to actually attach the sorting behavior to the HTML element uses the popular getElementsByClassName() function for which there are several different custom implementations or approaches. Because it is such a popular function, we shortened the name to $$. We can use the $$ function in our bootstrapper along with the makeSortable() function to add the sorting behavior to our HTML table.
function initSortable() { entAjax.lang.forEach( entAjax.html.$$("sortable"), entAjax.behaviour.makeSortable ); }

154

Chapter 4

AJAX Components

entAjax.behaviour.makeSortable = function(table) { entAjax.forEach(table.rows[0].cells, function(item) { item.className += " button"; }); entAjax.html.attachEvent(table.rows[0], "click", entAjax.lang.close(table, sort)); }

For a sortable HTML table, we require the makeSortable() function to do a few things. Each table that we want to have made sortable needs to have an additional class added to each header cell and an event handler function attached to the click event of the table header. To indicate to the end user that they can click on the column header to sort the table by that column, we add the button class that changes the users mouse cursors to a hand icons; when they click, it causes the global sort() function to be executed in the context of the HTML <table> element. (You remember from Chapter 2 that running the event handler in the context of the HTML element means the this keyword refers to the HTML element that makes writing the sort function a bit easier.) The sorting of data is something that we should all remember from Computer Science 101. JavaScript is no different from other languages in this regard, and we use the familiar bubble sort algorithm to order our table rows. We can also consider using the JavaScript array sorting functionality; however, it requires a bit more tedious overhead such as copying values between arrays and the like. The sort() function is shown here:
function sort(evtObj, element) { var aRows = this.rows; var nRows = aRows.length; var nCol = getCol(evtObj.srcElement); var swapped; while (true) { swapped = false; for (var i=1; i<nRows-2; i++) { var sValue1 =

Custom Declarative Components

155

aRows[i].cells[nCol].getAttribute("value"); var sValue2 = aRows[i+1].cells[nCol].getAttribute("value"); if (sValue1 > sValue2) { a.parentNode.insertBefore(a, entAjax.dom.getNextSibling(b)); swapped = true; } else { swapped = false || swapped; } } if (!swapped) break; } }

Because the sort() function is executed in the context of the HTML table element, we can access the collection of table rows using the native table rows property and similarly access the collection of cells in each row using the cells property. To get the value that is rendered in each cell of the table, rather than using something such as innerHTML that returns the rendered value of the cell, we instead get the custom VALUE attribute that we created ourselves (this might be an instance where you want to use a custom namespaced attribute) and which contains the raw, unformatted data. This is an important consideration when we deal with things such as prices that might be prepended with a "$" character for rendering but sorted as numbers. Having said that, after we dynamically connect our table to a datasource, this will no longer be necessary. Finally, we use some more native DOM manipulation methods such as element.insert Before(newNode, refNode). The insertBefore() method makes sorting the rows quite simple in that we can use that method with DOM nodes that are already renderedin this case, the table rowsand it actually moves those nodes and re-renders them. That is all there is to building a small behavioral AJAX component that can be layered on top of an existing web application. The entire idea behind behavioral components is gaining popularity from the world of semantic markup and other technologies such as Microformats. Strictly speaking, a Microformat is not a new technology but instead a set of simple

156

Chapter 4

AJAX Components

data formatting standards to provide more richly annotated content in web pages. Microformats use the same CSS class extension approach to give general XHTML content more semantic information. Microformats and other burgeoning standards such as the W3C endorsed RDFa are great places to watch to get an idea of where web technologies are heading and finding the best way to create declarative AJAX components. At any rate, behavioral AJAX using HTML declarations sprinkled with some additional metadata can be a great approach for AJAX development because it can be achieved in an incremental manner, thus avoiding any large up-front investment in training or technology. It can be a great way to test the AJAX waters before a more large scale deployment. Of course, there are still other ways to use your existing architecture when moving toward AJAXifying your applications.

Declarative Component
The next step beyond a behavioral component that uses HTML markup as the declaration is to create an abstraction of the HTML markup so that you can do more than just add some simple sorting or editing functionality. Using a custom-designed declaration means you can actually generate and output the HTML markup in the web browser populated with data from a client-side datasourcethis will be your fully declarative client-side AJAX solution. You need to consider a few aspects when making a custom declarative AJAX component or application. For some insight into these issues, as we have already mentioned, it is always a good idea to look at existing recommendations and specifications put forward by the W3Cno matter how esoteric or generally unrealistic they might sometimes seem. It seems more often than not that just because AJAX seems shiny and new, people tend to forget that most of what they want to do has been figured out in the past in one context or another. When it comes to creating a declarative AJAX solution, you can look for inspiration in a number of places. From looking at the many good examples of declarative frameworks currently available from private vendors such as Microsoft (XML Application Markup Language) and Adobe (Flex MXML) as well as the W3C (XForms, Scalable Vector Graphics, XML Binding Language), two common themes appear in all of them. These themes are data bindingdefining how and where data shows up in a user interface and data templatingdefining how the data is formatted in the user interface. We look at some existing solutions and some ideas for custom JavaScript approaches to both of these problems.

Custom Declarative Components

157

Databinding

A good solution for databinding can be a difficult thing to achieve. By good, we mean a solution that is flexible and provides multiple levels of indirection so that we can build complex data-bound components. To start with, lets take a quick look at a few of the data-binding solutions that have been prevalent on the web over the past decade.

Internet Explorer Databinding


Since version 4.0 came out, Internet Explorer has had client-side databinding functionality baked into the browser. Although it is nothing too advanced, Internet Explorer does provide basic data-binding functionality by supporting two custom HTML attributesthe DATASRC and DATAFLD attributeson several different HTML elements. The DATASRC attribute specifies a client-side datasource to which the element is bound whereas the DATAFLD attribute specifies the specific field in the datasource to which the value of an HTML element is bound. The most common HTML element to bind to a datasource is, as in our behavioral example, the <table> element, which is usually found bound to a repeating list of data where the list of data is repeated in <tr> elements of the table. A data bound <table> element might look like this:
<table datasrc="#products"> <thead> <tr><td>Product</td><td>Price</td></tr> </thead> <tbody> <tr> <td><span datafld="name"></span></td> <td><span datafld="price"></span></td> </tr> </tbody> </table>

Because the <td> element is one that does not support the datafld attribute, we use a <span> tag that is bound to a field from the datasource. Datasources themselves can be various structures; the most popular of which is likely the XML data island that looks like this:
<xml id="products" src="products.xml"></xml>

158

Chapter 4

AJAX Components

Although this is a useful technology, there is still much to be desired, and it provides little more than a stop gap when it comes to building true RIAs. More recently, W3C-supported technologies such as XForms and the XML binding language (XBL) are excellent examples of thorough approaches to declarative components and databinding in the web browser.

XForms Databinding
One of the most mature options on the list is XForms.1 XForms 1.0 became a W3C recommendation in October 2003 and has not moved much beyond that. There are some real advocates of the technology, but it is yet to be championed by mainstream browsers. In the XForms world, there are Models and controls (or Views). Models define the data and controls that are used to display the data. To bind the View to the Model, a few important declarative attributes need to be understood. First, you have single-node binding attributes. These define a binding between a form control or an action and an instance data node defined by an XPath expression. On an XForms control bound to a single data node, there can be either a REF and a MODEL attribute or a BIND attribute. The MODEL and REF attributes together specify the ID of the XForms Model that is to be associated with this binding element and the XPath of the data within that Model, respectively. Alternatively, this binding information might be contained in a completely separate declaration that can be referenced using the value of the third attribute of interest that has the name BIND. When you want to bind to a list of data rather than a single value, you can bind to a node-set rather than a single node in the Model. The NODESET attribute, much like the REF attribute, specifies the XPath to the nodes-set to which the control is bound. Again, either a MODEL attribute is required to go along with the NODESET attribute or a BIND attribute can refer to a separate binding declaration. Binding declaration elements, rather than just those four attributes, provide a more complete set of options for specifying how the binding to the data is to take place. The <BIND> element connects a Model to the user interface with these additional attributes: calculateSpecifies a formula to calculate values for instance data constraintEnables the user to specify a predicate that must be evaluated for the data to considered valid
1http://www.w3.org/TR/xforms

Custom Declarative Components

159

requiredSpecifies if the data required readonlySpecifies if the data can be modified typeSpecifies a schema data-type A final consideration is the evaluation context of the REF or NODESET XPath expressions. The context for evaluating the XPath expressions for data binding is derived from the ancestor nodes of the bound node. For example, setting REF="products/product" on a parent node results in the evaluation context for XPath expressions of descendent nodes to be that same path in the specified MODEL. For a select form element, you can use the <ITEMSET> element to define a dynamic list of values that are populated from the Model with ID products, and the selected products are saved in the Model with ID order.
<select model="order" ref="my:order"> <label>Products</label> <itemset model="products" nodeset="/acme:products/acme:product"> <label ref="acme:name"/> <value ref="acme:name"/> </itemset> </select>

Because of the evaluation context, the <LABEL> and <VALUE> REF XPath values are evaluated in the context of their direct parent node, which is the root node of the products Model. There are still more examples of declarative programming in the multitude of server or desktop languages that we could investigate such as .NET Web Forms, JavaServer Faces, Flex MXML, XUL, Laszlo, and XAML. What we can say is that most of these technologies are driven by the MVC pattern with extreme care taken to separate the Model and View. Like XForms, most also rely on XML-based data and leverage standards such as XPath and XSLT to achieve the rich functionality that you would expect from an RIA. In particular, some common threads in many of the new languages are the use of XPath in databinding expressions and the inheritance of the XPath execution context within the Model.

160

Chapter 4

AJAX Components

Templating

The second important area of building declarative components is templating of data. Templating of data is important if reuse is a priority because it should enable a high degree of customization to the component look and feel. Choosing a robust templating mechanism is a real key to creating flexible and high-performance AJAX applications and components. A few different JavaScript templating libraries are available on the web, the most popular of which is likely the JST library from TrimPath. As with many script-based templating languages (think ASP and PHP, for example), it inevitably turns out to be a mess of interspersed JavaScript code and HTML snippitsactually no different from writing JavaScript by hand. A JST-based template might look something like this:
Hello ${customer.first} ${customer.last}.<br/> <table> <tr><td>Name</td><td>Price</td></tr> {for p in products} <tr> <td>${p.name}</td><td>${p.price}</td> </tr> {forelse} <tr><td colspan="2">No products in your cart.</tr> {/for} </table>

As mentioned, this template looks rather similar to what you might use if you were to generate the HTML by standard string concatenation like this.
var s = ""; s += "Hello "+ obj.customer.first+" "+obj.customer.last+".<br/>"; s += "<table>"; s += "<tr><td>Name</td><td>Price</td></tr>"; for (var i=0; i<obj.products.length) { var p = obj.products[i]; s += "<tr><td>"+p.name +"</td><td>"+p.price+"</td></tr>"; } if (obj.products.length == 0)

Custom Declarative Components

161

s += "<tr><td colspan="2">No products in your cart.</tr>"; s += "</table>"; $("TemplatePlaceholder").innerHTML = s;

Although it might be a template by name, for all intents and purposes both of these approaches are essentially identical, and neither of them provide any of the benefits you should reap from using a templating solution. Namely, there are two primary benefits that you should expect from templating. First and foremost, templating should preferably not expose user interface developers to JavaScript coding and at the very least provide a solution for applying a template to a list of items without requiring an explicit for loop. Second, templating should make possible the creation of granular, decoupled templates, which promotes reuse and less error-prone customization. Although there might be a bit of a learning curve, both of these are well achieved by a true templating language such as XSLT, which can be a high-performance and versatile templating solution. XSLT has several advantages when it comes to the realities of implementing some templating solutions, such as good documentation (it is a W3C standard after all), granular templating, template importing capabilitiesamong many others. An often cited complaint of XSLT is that it is not supported in some browser. However, not only is XSLT supported in the latest versions of Internet Explorer, Firefox, Safari, and Opera, but you can also use the exact XSLT on the server to render data for user agents that do not support the technology. A basic XSLT stylesheet looks something like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <table> <xsl:apply-template select="//Product" /> </table> </xsl:template> <xsl:template match="Product"> <tr> <td><xsl:value-of select="Name"/></td> <td><xsl:value-of select="Price"/></td> </tr> </xsl:template> </xsl:stylesheet>

162

Chapter 4

AJAX Components

The values of Name and Price are retrieved based on the XML data that the template is applied to. Any <xsl:apply-templates select="Product"/> statements can result in that template being applied. To realize the real power of XSLT, you can do things such as append a predicate to a node selection <xsl:apply-templates select="Product[Price>10]"/> and even search entire subtrees of data just by prepending the select statement with //. XSLT also chooses the appropriate template to apply based on the specificity of the selector much like CSS. For example, to apply different styling to products with different prices, you can use the following XSLT:
<! this is the default template that will get applied > <xsl:template match="Product"> <tr> <td><xsl:value-of select="Name"/></td> <td><xsl:value-of select="Price"/></td> </tr> </xsl:template> <! this is a more specific template > <xsl:template match="Product[Name='Acme Widget']"> <tr class="sale-product"> <td><xsl:value-of select="Name"/></td> <td><xsl:value-of select="Price"/></td> </tr> </xsl:template>

The above templates render regular product items in a <tr> tag for placement in a table and render products where the name is Acme Widget with a CSS class that indicates the item is a sale product. Extensibility is a key feature of XSLT; given that the word extensible is in the name, you should expect as much. By using granular templates at this level, you can add or remove templates to the rendering, and the XSLT processor automatically chooses the most appropriate one. This is a deviation from other templating approaches that would likely depend on an imperative or imperative approach using an explicit if statement to check the product name. There can be tradeoffs with execution speed and code size depending on where extensibility is important to your component or application rendering.

Custom Declarative Components

163

It is certainly possible, with a little effort, to replicate the functionality of XSLT in native JavaScript. Again, tradeoffs can be speed and code size; however, you do get the advantage of all their code running in the same JavaScript execution sandbox making customization and some AJAX functionality a lot easier. One instance of this is in an editable DataGrid where rendered cell values can be editing by the end user, and then subsequently the new values can be saved on the server using AJAXwithout a page refresh or server post-back. If there is numeric data displayed in the DataGrid, such as the product price in our example, the price needs to be formatted according to a specific number mask to be displayed with the correct currency symbol and number formatting for the location. At first, this seems easy, but there are actually several data interactions that you need to consider. The number mask needs to be applied to the data in several cases, such as the following:

Initial rendering with all of the data After the value is edited When a new row is inserted into the DataGrid

Three distinct cases require three different levels of templates to make these sort of interactions as fluid as possiblethus, the motivation for having as granular templates as possible. We can always depend on just the first of those templates, the initial rendering template, which would certainly achieve the goal of redisplaying edited data with the proper formatting or displaying a newly inserted row; however, this would also entail a large performance hit because rerendering all the contents of the DataGrid would make editing data slow and tedious. Instead, we want to have templates for rendering blocks of data that rely on templates for rendering single rows of data that correspondingly rely on cell rendering templates.

The Declaration
Now that we have looked at the importance of databinding and templating to building our AJAX components and applications, we can look at how to create an abstract declaration for a DataGrid component. To create a declarative DataGridor any other component for that matterit is easiest to start by looking at the end product of the rendered HTML and then refactoring to break out the configurable aspects, as we did when looking at a behavioral component. Here is the first pass at defining a custom

164

Chapter 4

AJAX Components

declaration for the behavioral DataGrid that we have already looked at. Note that we still use standard HTML markup but that will change.
<table id="myGridList" class="grid"> <thead> <tr id="header" class="header-group"> <td id="header-0" class="header header-0">Product</td> <td id="header-1" class="header header-1">Price</td> </tr> </thead> <tbody> <tr id="row-template" class="row-template"> <td id="cell-{$Index}_0" class="column column0">{$Name}</td> <td id="cell-{$Index}_1" class="column column1">${$Price}</td> </tr> </tbody> <tfoot> <tr id="footer" class="footer-group"> <td id="footer-0" class="footer footer-0">Total</td> <td id="footer-1" class="footer footer-1">${$Total}</td> </tr> </tfoot> </table>

There is not that much difference here from our behavioral DataGrid HTML; we have the static header and footer of the DataGrid, as we did previously; however, we have now specified a template for the grid rows to be rendered with rather than having the data for each row explicitly written in HTML. In place of the product name and price values, we have a new syntax that looks something like this {$FieldName}. This syntax, which is borrowed from XSLT, is used to indicate where the data from the datasource should be placed, and the string after the $ character should correspond to a data field in the client side datasource, which could be XML, JSON, or otherwise. Based on what we see in other declarative languages, it would make most sense to use XPath expressions here. After connecting this View to the Model, what we ideally end up with is a rendered grid where the {$FieldName} expressions are all replaced with data from the client side datasource. Assuming that the template is applied to a list of data, we also use the {$Index} expression to render out the

Custom Declarative Components

165

unique numeric index of each item in the collection. In this case, we use this index value to generate a dynamic CSS class name in the HTML that we also create dynamically from JavaScript. You can also be quick to notice that there is a problem here in that the footer of the grid contains the sum of the values in the price column and, therefore, must be calculated dynamically. Also notice that the text that appears at the top of each column, as well as the HTML element styles, and even what HTML elements are used for the structure, are all still statically defined in the HTML which can drastically increase the probability of human error when defining the appearance of the component and dramatically impact usability and user interface skinability. That being said, there are certainly instances where this degree of flexibilityas in the case of the behavioral componentcan be advantageous. At any rate, we can get around this problem of having all class names defined explicitly by using an even more abstract representation of our DataGrid. For example, although we have now defined a row-based template for the data contents of our DataGrid, we can also consider binding the header of the DataGrid to a datasource using a template such as this:
<tr id="header-template" class="header-template"> <td id="header-{$Index}" class="header header-{$Index}">{$Label}</td> </tr>

The <td> element is repeated for each column defined. In this case, the columns are not bound to the data in our primary Model that contains the product information but instead to another pseudo Model that contains information about the columns such as the column label, width, styles, and other information, such as whether the data in the column is to be summed. This enables us to template the grid header so that each column header can be rendered out to the DOM using this simple HTML template as well. Something similar can be devised for the footer; however, depending on the application scope, things can become complicated quickly. The nature of a grid is based on columns of data; columns are the basic building block of a grid and contain all the necessary information such as the column header, column footer, and column data. Thinking about the class diagram of a grid, you can quickly realize that rather than trying to fit a rich grid structure to an entirely HTML-based definition, it can be far easierboth for the developer of the component and the application

166

Chapter 4

AJAX Components

designer using the componentto define a declaration using custom HTML tags. A declaration that make things a bit easier for an application designer might look something like this:
<ntb:grid datasource="products" cssclass="myGrid"> <ntb:columns> <ntb:column width="100px"> <ntb:header value="Name"></ntb:header> <ntb:item value="{$Name}"></ntb:item> <ntb:footer value="Total" style="fontweight:bold;"></ntb:footer> </ntb:column> <ntb:column width="100px"> <ntb:header value="Price"></ntb:header> <ntb:item value="{$Price}" mask="$#.00"></ntb:item> <ntb:footer value="{SUM($Price)}" style="font-weight:bold;"></ntb:footer> </ntb:column> </ntb:columns> </ntb:grid>

This looks similar to the explicit HTML; however, it differs in a few important ways. The definition of the grid has been pivoted so that we consider the grid from the point of view of the columns, where each column has a header, data items, and footer, rather than from the point of view of the rows. By doing this simple change, it significantly simplifies the way we approach templating and databinding. In the case of a DataGrid, we need several different templates. We need to template the DataGrid itself:
<table id ="{$id}" class="simplegrid">{$Header}{$Data}{$Footer}</table>

The header group template:


<tr id="{$id}-header" class="header-group">{$columns}</tr>

The header item template:


<td id="{$_parent.id}-header-{$index}" class="header header{$index}" style="width:{$columnWidth};">{$header.value}</td>

Custom Declarative Components

167

The row item template:


<tr id="{$id}-row-{$index}" class="row {$AltRowClass}" eatype="row">{$columns}</tr>

The cell item template:


<td id="{$id}-cell-{$RowIndex}_{$index}" class="column column{$index}" eatype="cell">{$item.value}</td>

The footer group template:


<tr id="{$id}-footer" class="footer-group">{$columns}</tr>

And finally, the footer item template:


<td id="{$id}-footer-{$index}" class="footer footer{$index}">{$footer.value}</td>

With a DataGrid type control, the templates are rather difficult as some of the templates depend on two sources of data. In particular, the templates are first bound to the state of the DataGrid; this ensures that the widths and styles of all the columns are set correctly according to the state of the DataGrid itself. The second binding takes place when the DataGrid binds to an external datasource as specified in the DataGrid state. The data cell item template is the most complicated template because it must contain information provided from both the state of the DataGridit needs to have certain formatting applied depending on the data type, for exampleas well as information from the externally bound datasource. To ensure that each cell in the DataGrid is uniquely addressable, we generate the id attribute of the <td> element as id="{$id}cell-{$RowIndex}_{$index}" where {$id} comes from the Data Grid statethe unique indentifier of the DataGrid itself{$index} is the index of the column, and {$RowIndex} is the index of the row. For all the details about the templating approach, you have to look through the source code provided with the book. With this array of granular templates, you can render the component quickly and efficiently at various points throughout the component lifetime, such as when the component is rendered, when data is edited, or when data is created or deleted.

168

Chapter 4

AJAX Components

Building the Component


It is easiest to start by building the imperative version of the component and then enabling the use of a declaration to preset any component parameters. This approach is generally a wise one because it ensures a quality API from the point of view of an imperative developer, and it makes the component accessible to those that dont want to use the declaration. Lets look at how to build a declarative component for an application in which we want a list of Customers presented to a user that is populated from a server-side data handler using AJAX.

Basic Functionality
As a first requirement, we create our DataGrid control in the exact same way as any other instance of a class using the new keyword and pass the HTML element as a single constructor argument that refers to the element in which we want our component to be rendered in. However, as with any development effort, whether you use Extreme Programming or the Waterfall approach, we start by doing at least a bit of design up front. A DataGrid control can be represented fairly simply in a UML class diagram, as shown in Figure 4.3.
class SimpleGrid

class Component attributes: Array element: HTMLElement elements: Array id: char renderTemplates: Object Component class SimpleGrid + * 1 + + + columns: SimpleGridColumn (Array) cssClass: char cssStyle: char dataSource: DataModel footerPreProcessor: Processor headerPreProcessor: Processor itemPreProcessor: Processor template: char dispose() : void render() : void renderReady() : void setDataSource(DataModel) : void

+ deserialize() : void

class SimpleGridColumn cssClass: char cssStyle: char footer: ColumnFooter header: ColumnHeader item: ColumnItem width: int

Figure 4.3 SimpleGrid Class Diagram

Building the Component

169

The SimpleGrid class consists of a collection of column definitions, header and footer, and collection of rows. Furthermore, there are a number of methods that are inherited from the Component class that are used by the declarative framework to instantiate, render, and destroy the component, such as render() and dispose(). There is a one-to-many relationship between the SimpleGrid and the Column class where the Column class contains all the information needed to render a column of data such as the column header, footer, data, width, type, and CSS properties. Similarly, the SimpleGrid class inherits from the Component class where all the requisite functionality for declaration parsing and templating is defined. Because we design our component from a UML model, we take advantage of that and actually generate the scaffolding JavaScript code for our component including getters and setters for all the properties, method stubs, and the inheritance chain. So, to start, we get quite a bit for free just from using the tools that we have traditionally used for server or desktop development in C++ or Java. Our initial SimpleGrid constructor and Component class look something like this:
entAjax.Component = function(element) { this.element = element; this.id = element.getAttribute("id"); this.renderTemplates = {}; this.attributes = ["id","datasource","cssclass","cssstyle"]; this.elements = []; } entAjax.Component.prototype.deserialize = function() { for (var i=0; i<this.attributes.length; i++) { var attr = this.attributes[i]; this[attr] = this.element.getAttribute(attr); } } entAjax.SimpleGrid = function(element) { entAjax.SimpleGrid.baseConstructor.call(this, element); // Collection of column objects this.columns = []; // Basic template for the entire component this.template = '<table id ="{$id}" class="simplegrid">{$Header}{$Data}{$Footer}</table>';

170

Chapter 4

AJAX Components

// Header templates this.headerPreProcessor = new entAjax.Processor({ "root":{"predicate":"true","template":'<tr id="{$id}header" class="header-group">{$columns}</tr>'}, "columns":{"predicate":"true","template":'<td id="{$_parent.id}-header-{$index}" class="header header{$index}" style="width:{$columnWidth};">{$header.value}</td>'} }); // Data row templates this.rowPreProcessor = new entAjax.Processor({ "root":{"predicate":"true","template":'<tr id="{$id}-row{$index}" class="row {$AltRowClass}" eatype="row">{$columns}</tr>'}, "columns":{"predicate":"true","template":'<td id="{$id}cell-{$index}_{$index}" class="column column-{$index}" eatype="cell">{$item.value}</td>'} }); // Footer templates this.footerPreProcessor = new entAjax.Processor({ "root":{"predicate":"true","template":'<tr id="{$id}footer" class="footer-group">{$columns}</tr>'}, "columns":{"predicate":"true","template":'<td id="{$id}footer-{$index}" class="footer footer{$index}">{$footer.value}</td>'} }); } entAjax.extend(entAjax.SimpleGrid, entAjax.Component);

In the SimpleGrid constructor, all we have done is create the three different template processors for the header, footer, and the data with some initial default templates. What happen to these templates is that the information from the DataGrid declaration merges with the initial templates to produce secondary templates. The advantage of doing this is that the declaration might not change during the lifetime of the component, yet the data is likely to change. With that in mind, after merging the declaration information with the templates, we cache the result so that we can reuse those generated templates as the data changes and make the templating process much more efficient.

Building the Component

171

To instantiate an instance of the SimpleGrid class based on an XHTML declaration, we use the following deserialize method, which also uses the generic deserialization method of the Component base class:
entAjax.SimpleGrid.prototype.deserialize = function() { entAjax.SimpleGrid.base.deserialize.call(this); // Iterate over the <ea:column> elements var columns = entAjax.html.getElementsByTagNameNS("column","ea",this.element ); for (var i=0; i<columns.length; i++) { // Create a new SimpleGridColumn for each declaration column this.columns.push(new entAjax.SimpleGridColumn({"element":columns[i],"index":this.co lumns.length+1})); } // Cache results of the generated templates based on the declaration this.rowTemplate = this.rowPreProcessor.applyTemplate(this); this.headerTemplate = this.headerPreProcessor.applyTemplate(this); this.footerTemplate = this.footerPreProcessor.applyTemplate(this); }

The deserialization method is responsible for finding elements in the declaration and copying those attributes from the XHTML element to the JavaScript object. In the case of the SimpleGrid class, it copies over attributes from the <ea:grid> XHTML element and then proceeds to search for any <ea:column> elements that are then deserialized into SimpleGridColumn JavaScript objects and added the columns collection of the DataGrid. The SimpleGridColumn objects also deserialize the declaration further to get information about the column header, data, and footer.

172

Chapter 4

AJAX Components

At this point, we deserialize the state of the SimpleDataGrid from an XHTML declaration into a JavaScript object with just two lines of JavaScript code:
var grid = new entAjax.SimpleGrid($("myGrid")); grid.deserialize();

where myGrid is the id of the declaration in the web page. To bring everything together and actually get the component to automatically deserialize, we use the same initComponents() function we used when converting the Google Map to be a declarative component. All we need to do is create a factory method that is responsible for creating an instance of the SimpleGrid class and put a reference to that method in the global hash table that maps XHTML element names to their respective factory methods:
entAjax.GridFactory = { "fromDeclaration": function(elem) { var grid = new entAjax.SimpleGrid(elem); grid.deserialize(); } } entAjax.elements = {"grid":{"method":entAjax.GridFactory.fromDeclaration}};

Now, our DataGrid is still not rendering and it doesnt have any data to render. We can remedy this by adding the render method to the SimpleGrid class that looks like this:
entAjax.SimpleGrid.prototype.render = function() { this.renderTemplates["root"] = {"predicate":"true","template":this.template}; this.renderTemplates["Header"] = {"predicate":"true","template":this.headerTemplate}; this.renderTemplates["items"] = {"predicate":"true","template":this.rowTemplate}; this.renderTemplates["Footer"] = {"predicate":"true","template":this.footerTemplate};

Building the Component

173

this.renderTemplates["AltRowClass"] = {"predicate":"true","template":altRowColor}; // Create a container for the component and show a loading indicator this.container = document.createElement("div"); this.element.appendChild(this.container); // Create the processor for the cached templates. this.gridProcessor = new entAjax.Processor(this.renderTemplates); // Generate the content from the templates and the data var html = this.gridProcessor.applyTemplate(this.dataSource.items); this.container.innerHTML = html; }

The render method takes the cached rendering templates that were created in the deserialization method and applies those generated templates to the data, which results in the contents of the DataGrid being generated after which that content is placed into the web page DOM using the innerHTML property of the XHTML declaration element. The dataSource field of the SimpleDataGrid containing the data to be rendered can be populated simply by setting it to some static array of customer data like this:
grid.dataSource = {"items":[{"Name":"Joe","Company":"Acme"},{"Name":"Bob","Compa ny":"Widgets'r'us"}]};

Connecting to the Server


Rendering static data is hardly that useful in an enterprise application, so lets connect to the server. To retrieve data from the server, we need to go back to our SimpleDataModel class and give it some teeth. The first step for creating a remote datasource is retrieving the data from the serverwe deal with inserting, updating, and deleting later. The UML diagram for the RemoteDataModel class looks like Figure 4.4.

174

Chapter 4

AJAX Components

class RemoteDataModel

Object class SimpleDataModel columns: Column [0..*] items: Object + + + + create() : void delete() : void read() : void update() : void class RemoteDataModel handler: char itemFactory: Object m_httpRequest: HttpRequest onDataReady: SubjectHelper

m_readComplete() : void + read() : void

Figure 4.4 RemoteDataModel Class Diagram The important new features of the RemoteDataModel compared to the SimpleDataModel are the private m_httpRequest for retrieving data from the server, the onDataReady event for notifying interested parties when the data is ready for consumption, the m_readComplete method that handles the asynchronous callback from the XHR object when the data has been retrieved from the server, and finally, the itemFactory object that we use to deserialize XML data from the server into JavaScript objects. The code for the RemoteDataModel follows:
entAjax.RemoteDataModel = function(items) { // Call the base constructor to initialize the event objects entAjax.RemoteDataModel.baseConstructor.call(this); // onDataReady will fire when data is ready for use this.onDataReady = new entAjax.SubjectHelper(); // The handler is the URL of the data on the server this.handler = ""; // To enable the RemoteDataModel to create any type of object this.itemFactory; // Internal XHR object for retrieving data from the server this.m_httpRequest = new entAjax.HttpRequest(); }

Building the Component

175

// Inherit from SimpleDataModel entAjax.extend(entAjax.RemoteDataModel, entAjax.SimpleDataModel); entAjax.RemoteDataModel.prototype.read = function() { // Request the data from the server and call m_readComplete // when the data is ready this.m_httpRequest.completeCallback = entAjax.close(this, this.m_readComplete); this.m_httpRequest.handler = this.handler; this.m_httpRequest.get(); } entAjax.RemoteDataModel.prototype.m_readComplete = function(serverResponseArgs) { this.items = []; // This should be encapsulated but is ok for now var data = serverResponseArgs.response.documentElement.childNodes; // Loop though each XML element returned and deserialize it for (var i=0; i<data.length; i++) { this.items.push(this.itemFactory.fromXml(data[i])); } // Let everyone know that the data is ready this.onDataReady.notify(this, serverResponseArgs); }

Consider a few important points about the RemoteDataModel class. First, we request the data from the server asynchronouslyat the URL specified by the handler fieldso the read() method no longer directly returns data; the read() method no longer blocks the JavaScript thread until data is ready to be returned and instead sends the request for data to the server and immediately returns with no return value. The data is actually returned from the new method we added called m_readComplete(), which is executed when the data has finally been returned from the server. Just like the callback function that we use on the plain XHR object to be notified when an asynchronous request has been completed, we now need to apply that same pattern to our custom JavaScript classes that rely on

176

Chapter 4

AJAX Components

asynchronous server requests. Thus, we have introduced the onData Ready event to which handlers can be subscribed and, hence, notified when the data is indeed ready. The second important point about the RemoteDataModel class is that rather than returning JSON from our web service on the server, we return plain XML, which this is another aspect that can be factored out to create a RemoteXMLDataModel and RemoteJSONDataModel. A problem arises here because our DataGrid component relies on JavaScript-based templating and, therefore, expects an array of JavaScript objects as the items field on a datasource object. To achieve this, we made the itemFactory field on the RemoteDataModel that is used to enable the user to specify a factory object that will provide a fromXml method that will return a JavaScript object based on the information in an XML element returned from the server. In this case, we want to create Customer objects, and we set the itemFactory field of the RemoteDataModel to an instance of the CustomerFactory class:
entAjax.CustomerFactory = function(){} entAjax.CustomerFactory.prototype.fromXml = function(element) { return new entAjax.Customer(element); }

Now we have a choice to make as to how we actually instantiate the Customer class, and we have decided to depend on the class itself to do the deserialization from an XML element. The alternative would be to create an instance of the Customer class and then set all the relevant fields from the outside. To achieve this deserialization, we created a basic Serializable class as follows:
entAjax.Serializable.prototype.deserialize = function() { for (var item in this) { if (typeof this[item] == "string") { var attr = this.element.getAttribute(item); if (attr != null) { this[item] = attr; } } } }

Building the Component

177

This loops through the attributes on the XML element from which the object is to be deserialized and copies each attribute name and value pair onto the JavaScript object. The Customer class looks like this:
entAjax.Customer = function(element) { this.CustomerID=""; this.CustomerName=""; this.ContactName=""; this.ContactEmail=""; this.ContactTitle=""; this.PhoneNumber=""; this.Address=""; this.Country=""; this.RegionID=""; entAjax.Customer.baseConstructor.call(this, element); } entAjax.extend(entAjax.Customer, entAjax.Serializable);

Closing the Loop


Now that we have a RemoteDataModel that our DataGrid can connect to, we need to actually connect them. To achieve this, we can update the GridFactory fromDeclaration() method so that it also creates an instance of the RemoteDataModel class and specifies the appropriate factory for the RemoteDataModel itemFactoryin this case, the Customer Factory because our DataGrid is rendering Customer objects.
entAjax.GridFactory = { "fromDeclaration": function(elem) { var grid = new entAjax.SimpleGrid(elem); grid.deserialize(); var rdm = new entAjax.RemoteDataModel(); // need to get this from the datagrid... rdm.itemFactory = new entAjax.CustomerFactory(); grid.setDataSource(rdm); } }

178

Chapter 4

AJAX Components

The setDataSource() method of the DataGrid will do a few things, such as ensure that the supplied datasource actually inherits from the DataModel class, sets the handler field on the remote datasource to the URL of the server side data handler specified on the DataGrid declaration, and subscribes a new method of the SimpleDataGrid called m_render Ready() to the onDataReady event of the datasource.
entAjax.SimpleGrid.prototype.setDataSource = function(dataSource) { if (dataSource instanceof entAjax.DataModel) { this.dataSource = dataSource; this.dataSource.handler = this.handler; this.dataSource.onDataReady.subscribe(this.m_renderReady, this); } }

Due to the asynchronous nature of the data retrieval now, the DataGrid render() method needs to be reconsidered. The render() method will no longer actually do any rendering but instead simply call the read() method on the datasource. The datasource will then asynchronously request the data from the server and notify all subscribers to the onDataReady eventone of those subscribers just so happens to be the m_renderReady event of the DataGrid, and that is where the actual rendering code gets moved to.
entAjax.SimpleGrid.prototype.m_renderReady = function() { var html = this.gridProcessor.applyTemplate(this.dataSource.items); // Remove any activity indicators that were displayed this.loadingComplete(); // Set the contents of the component to the generated HTML this.container.innerHTML = html; }

The final piece of the puzzle is adding a call to the DataGrids


render() method into the GridFactory such as this:
entAjax.GridFactory = { "fromDeclaration": function(elem) {

Building the Component

179

var grid = new entAjax.SimpleGrid(elem); grid.deserialize(); var rdm = new entAjax.RemoteDataModel(); rdm.itemFactory = new entAjax.CustomerFactory(); grid.setDataSource(rdm); grid.render(); } }

Now we have a fully operational DataGrid that is requesting data from the server and rendering it in the web browser! The full web page is shown here:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html xmlns:ea="http://www.enterpriseajax.com"> <head> <title>Component Grid</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <link rel="stylesheet" href="simplestyle.css" type="text/css"> <script language="javascript" type="text/javascript" src="entajax.toolkit.js"></script> <script language="javascript" type="text/javascript" src="RemoteDataModel.js"></script> <script language="javascript" type="text/javascript" src="SimpleDataGrid.js"></script> </head> <body> <ea:grid id="myGrid" handler="data.xml" cssclass="CustomerGrid"> <ea:columns> <ea:column width="100"> <ea:header value="Name" cssclass="myHeaderCSS"></ea:header> <ea:item value="{$ContactName)}" cssclass="myRowCSS"></ea:item> </ea:column> <ea:column width="100"> <ea:header value="Company"></ea:header>

180

Chapter 4

AJAX Components

<ea:item value="{$CompanyName}"></ea:item> </ea:column> </ea:columns> </ea:grid> </body> </html>

What you will likely notice is that in developing the component the way we did, we can also instantiate the component purely from JavaScript as if there is no declaration at all:
var grid = new entAjax.SimpleGrid(elem); // Setup all the columns through JavaScript grid.columns.push(new entAjax.SimpleDataGridColumn()); grid.columns[0].header = new entAjax.SimpleDataGridColumnHeader(); grid.columns[0].header.value = "ContactName"; grid.columns[0].item = new entAjax.SimpleDataGridColumnItem(); grid.columns[0].item.value = "{$ContactName}"; // Create and attach the datasource var rdm = new entAjax.RemoteDataModel(); rdm.itemFactory = new entAjax.CustomerFactory(); grid.setDataSource(rdm); // Render the component grid.render();

Summary
This chapter explained that there is a lot involved in not only developing an AJAX application, but also in having it interact with a users web browser. Through the course of this chapter, we looked at some of the differences between imperative and declarative approaches to developing AJAX applications and looked at a simple example of making the Google Map component declarative. We also looked at some of the important variations on declarative programming, most notably behavioral. Behavioral AJAX can be a great tool for taking pre-existing HTML markup and adding a little AJAX on top of it to make your application a little more interactive and usable. Using many of the JavaScript techniques, we went through the

Summary

181

entire process of developing a declarative DataGrid component from the ground up. In future chapters, we take a closer look at some of the nuances around various aspects of the DataGrid component in the context of a larger application.

Resources XForms, http://www.w3.org/MarkUp/Forms/XSLT, http://www.w3.org/TR/xslt JSONT, http://goessner.net/articles/jsont/ Internet Explorer databinding, http://msdn.microsoft.com/workshop/author/ databind/data_binding_node_entry.asp Google Maps, http://www.google.com/apis/maps/

I S B N : 0 -13 -13 4555 -9

B U Y TH E b OO K TO DAY

The Design of Sites


Patterns for Creating Winning Web Sites
Second Edition

DOUGLAS K. VAN DUYNE JAMES A. LANDAY JASON I. HONG

Upper Saddle River, NJ Boston Indianapolis San Francisco New York Toronto Montreal London Munich Paris Madrid Capetown Sydney Tokyo Singapore Mexico City

Customer-Centered Web Design: More Than a Good Idea

The World Wide Web is no longer a novelty. To many companies and organizations, the Web is a necessity, the foundation of their businesses. As the cost of maintaining a customer service operation increases, the ability of Web site visitors to find information and complete specific tasks themselves can easily mean the difference between profit and loss. Customer-centered Web site design is therefore no longer a luxury adopted only by forward-thinking companies with a special interest in customer satisfaction. Many of the design elements presented in this book are now the minimum requirements for an effective, professional Web site. As you work your way through the patterns that we discuss, consider how many highquality sites youve seen that use the techniques described, and how much thought must have gone into their development. Implementing a customer-centered design is relatively easy when you have examples to work from and a wheel that has already been invented. In this chapter you will discover the thinking behind customer-centered design and learn how to apply it to your projects using the principles, processes, and patterns that we present throughout this book.

1.1 The Evolution of Web Design


First Generation The mantra was build it, and they will come. Talented individuals and large teams alike built Web sites. These creative and visionary people managed everything from business planning to graphic design and software development in this new medium. Once having built the site, though, all they could say was that they had a Web site. They could not say how their

Customer-Centered Web Design: More Than a Good Idea

site was performing from the customers perspective, or how the site was related to the businesss bottom line. Second Generation The mantra was advertise that you sell it online, and they will come. Start-ups invested large amounts of capital in expensive ads to draw visitors to their e-commerce sites. Even established companies put .com on their letterhead and ran costly campaigns to let people know they hadnt been left behind. Unfortunately, this strategy did not work, because Web design was complex and still misunderstood. For the first time, organizations were building interactive computer interfaces to their products and services. This task proved to be difficult to execute well. Building a Web site too quickly, in fact, made its probability of being both compelling and easy to use practically zero. Third Generation With the first edition of this book we helped shift the mantra to customercentered designto constructing powerful Web sites that provide real value and deliver a positive customer experience.1 When visitors consistently give a Web site high marks for content, ease of use, performance, trustworthiness (as well as other indicators of brand value), and overall satisfaction, we call it a customer-centered Web site. Consideration of these additional factors is what differentiates customer-centered design from other design approaches (see Figure 1.1). Fourth Generation Today new technologies and business models have resulted in more innovative designs, but they also present greater challenges for building

1 We use the term customer rather than user for three reasons. First, only two types of businesspeople refer to their customers as users: drug dealers and computer companies. Second, and more importantly, the term customer evokes the idea that successful Web sites account for issues that go beyond ease of use and satisfaction, such as trustworthiness, brand value, and even how well a companys traditional interactions with the customer work, such as telephone-based customer service or the return of merchandise. Finally, taking a cue from Beyer and Holtzblatts Contextual Design, we use customer to refer to anyone who uses or depends on the site. Customers can be administrators, partners, managers, and producers, among others. To manage the site, many of these individuals will see a completely different interface. We chose the term customer because it is more expansive than user, referring to all of these individuals and their myriad needs.

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

Figure 1.1 The key issues driving customer-centered Web design.

Ease of Use

Content

Performance

Customer-Centered Web Design

Satisfaction

Brand Value

1.1

customer-centered Web sites. With the advent of AJAX (Asynchronous JavaScript And XML), the Mobile Web, and other Web 2.0 capabilities, sites can now provide features that are more compelling, more powerful, easier to access, and easier to use. However, building better interfaces now requires skills that are more specialized and harder than ever to acquire. In this edition of the book, we provide additional design patterns that enable you to build these customer experienceenhancing capabilities into your Web sites. The challenge to be customer centered exists for all enterprises: large multinationals, government agencies, internal corporate services, small businesses, and nonprofit organizations, to name just a few. General Motors, for example, must manage its customer experience for more than three hundred end-customer, supplier, and distributor Web sites. Government sites, with responsibilities to help the citizenry and other agencies, need to satisfy customer requirements as well. Intranet applications that optimize a corporations workforce must provide positive experiences to employee customers.

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

The Importance of Customer-Centered Design


Over the years we have learned that the criteria for building customercentered Web sites are based on providing a positive experience for all customers, whether those customers are there to find information, to be part of a community, to purchase items, or to be entertained. This focus is called customer-centered design. Customer-centered design increases the value of Web sites through better design and evaluation. It is about how you empathize with customershow well you understand their needs, the tools and technologies they use, and their social and organizational context. It is about how you use this understanding to shape your designs and then test those designs to ensure that the customers needs are met. Why go to all this trouble? What will happen if you dont? Suppose your site overruns its budget or schedule. Management could pull the plug before it is completed. Or what if your Web site is finished but turns out to be too hard to learn or use? Customers might visit your site once and never return. With customer-centered design, you do the work up front to ensure that the Web site has the features customers need, by determining and planning for the most important features and by making certain that those features are built in a way that customers will understand. This method actually takes less time and money to implement in the long run. In short, customer-centered design helps you build the right Web site and build the Web site right! Heres an example that underscores the importance of customercentered design. Several years ago, IBM found that its Web site was not working well. Quick analysis revealed that the search feature was the most used function. The site was so confusing that IBMs customers could not figure out how to find what they wanted. IBM also discovered that the help feature was the second most popular function. Because the search feature was ineffective, many people went to the help pages to find assistance. Paying close attention to customer needs, IBM redesigned the site from the ground up to be more consistent in its navigation. A week after launching the redesigned site, customers reliance on the search and help features dropped dramatically and online sales rose 400 percent. This is just one of many stories highlighting the increasing importance of good design. But does good Web design really affect the bottom line? You bet! Web sites founded on solid fundamentals and extensive customer research can make the difference between success and failure. A clear,

1.2

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

easy-to-use, and customer-centered Web site can help garner better reviews and ratings, reduce the number of mistakes made by customers, trim the time it takes to find things, and increase overall customer satisfaction. Furthermore, customers who really like a Web sites content and quality of service are more likely to tell their family, friends, and coworkers, thereby increasing the number of potential customers. A great example of this result is Google, which has become the dominant search site with little or no advertising. It simply works better than most other search sites, and customers tell their friends about it. There is also a strong correlation between increased satisfaction and increased profits for commercial Web sites. Underscoring this point, our research shows that increasing customer satisfaction by just 5 percent can lead to a 25 percent or greater increase in revenues. There are two reasons for the revenue increase and the related increase in profits. The first is that customers can find products and services more easily and are thus more likely to return in the future. The second is that support costs are reduced because of a lower number of phone calls, e-mails, and instant messages to help desks, as well as a lower number of product returns. The stakes are higher now than ever before. Commercial Web sites that are not relevant, fast, trustworthy, satisfying, and easy to use will have a hard time attracting new customers and retaining existing customers, especially if competitors are only a click away.

Providing Tangible Value


Yahoo! is one of the top Web sites today, and its likely to remain near the top for the foreseeable future. Why? Is it because it has slick graphic design? Hardly. Yahoo!s homepage uses graphical images sparingly, and most of its other pages have even fewer. Even though Yahoo! was once pointed to as the poster child of boring interfaces, its mostly text interface still is very quick to load because it has so few graphics. So why is Yahoo! so popular? Its pretty simple actually: Yahoo! provides quality services that are useful, fast to download, and easy to use. One of the reasons it is such a popular Web site is that interaction design and usability research are integral parts of Yahoo!s development process. Yahoo! identifies its customer needs through field studies, interviews, and usability evaluations, and then it tailors its designs to match those needs.

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

People will leave your Web site if they Are frustrated Think that navigating the site is too difficult Think that you dont have the product or service they want Get big surprises that they dont like Feel that the site takes too long to load

You cannot afford to abandon a single customer. Even if your site does not have direct competitors, as is the case with educational institutions and corporate intranets, it can benefit from being customer centered. Simple, clean, and well-designed Web sites can cut down on wasted time for customers, reduce Web site maintenance costs for clients, and improve overall satisfaction.

Our First Steps toward Unifying Design, Usability, and Marketing


In 1997 we noticed that a few companies had dramatically jumped ahead of the competition and were now leaders on the Web. These companies had publicly stated and acted on making the customer experience their top priority, and they raised the bar for everyone. While we were actively helping clients develop sites in an ever more competitive environment, we realized we had to move beyond the traditional boundaries of usability, market research, and software design. It was not an easy task, because our clients had committed to these means at varying levels, in different parts of the organization that usually did not talk to one another. Drawing on our experience in design, consulting, marketing, communications, and humancomputer interaction research, we evaluated our clients Web sites on many levels. We discovered that although a customer focus existed, often it was not reflected on the Web sites. We also discovered that some clients were not improving the customer experience on their Web sites at all. This was not surprising, considering that these companies did not have a clear Web strategy. It was not uncommon for a clients Web design team to have an inadequate budget and little authority to integrate operations with the rest of the company. Sometimes our clients were simply too busy trying to stay afloat to care about getting a full wind in their sails. One Web business we studied thought that it was doing very well with its health-related news, information, and products. It was receiving thousands of Web-based orders

1.3

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

per week. It spent heavily on advertising to draw people to its site, and as advertising spending increased, so did sales. Our team evaluated the ease of use of the site, doing some customer research over a short period of time (later well explain how you can run studies like this yourself). We looked at many factors, from first impression, to ease of use, to overall satisfaction. We found some surprising results that led us to important conclusions. The developers of the site had done a great job of creating a powerful first impression. All the customers in our research panel liked the site, thought it looked easy to use, and said it appeared to have relevant content. Next, however, we asked the same customers to use the site to carry out a realistic task: finding products for the common cold. Only 30 percent of the customers could find any products at all for colds, or for any other medical condition. This research suggested that about 70 percent of customers who came to the site to solve particular health problems could not find what they were looking for, revealing that, despite the companys perception that its Web site was serving it well, a substantial amount of revenue was being lost to user interface problems. The cost of dissatisfied customers abandonment of this site could have reached into the millions of dollars over the course of a year. Our experience with the health site is not uncommon. The bottom line is that poorly designed Web sites frustrate people, fritter away customer loyalty, and waste everyones time.

1.4 Why We Prefer Customer-Centered Design


One way to explain the value of customer-centered design is to compare it to other design styles. In this section we look at four styles centering in turn on the user, the company, technology, and the designer. User-Centered Design Customer-centered design is most closely related to what is known as user-centered design, an effort pioneered in the 1980s for engineering useful and usable computer systems. Customer-centered design builds on user-centered design, addressing concerns that go beyond ease of use and satisfaction. In particular, it also focuses on the fusion of marketing issues with usability issues. On the Web it is much easier to get an audience than by traditional means, but a trickier goal is to convert Web site visitors to customers and

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

keep them coming back. Unlike someone selling shrink-wrapped software to a customer who buys before using it, you want to convince Web site visitors to become customers while at the same time making their first use enjoyable. Pay special attention to business goals, marketing goals, usability goals, and customer experience goals. These goals often conflict with each other, and you will be able to find a balance among them only if you are aware of them all at once. These issues are much more intertwined and harder to design for on the Web than for shrinkwrapped software. Company-Centered Design A style that used to be quite popular among Fortune 500 companies is what we call company-centered design. Here the needs and interests of the company dominate the structure and content of the Web site. The fatal flaw is that what companies think should be on a Web site is not necessarily what customers need or want. You have probably seen Web sites that are organized by internal corporate structure, with sparse information about the products and services they offer. These kinds of sites are derisively termed brochureware. They contain little useful information and completely ignore the unique capabilities of the Web as a medium. Brochureware sites are acceptable only if they are a short-term first step toward more sophisticated and more useful sites. Another example of company-centered design is the use of jargon known only to those in the business. When one of our friends wanted to buy a digital camera, he turned to the Web for information. As an amateur, he wanted a camera that was easy to use, one that would help him take clear pictures. Most of the sites he found, though, bombarded him with terms like CCDs, FireWire, PC card slots, and uncompressed TIFF mode. The fact that he didnt know what these terms meant embarrassed him. He was put off and confused. The companies had made the wrong assumption about their customers knowledge. None of them answered the simple question of which camera was best for amateurs. This is an example of why company-centered design is almost always a bad style. Technology-Centered Design Sites constructed on the basis of technology-centered design are often built with little up-front research about business needs and customer needsjust a lot of hacking and caffeine. We have all seen Web sites like

10

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

thisthe ones overloaded with animation, audio, video, and streaming banners. The problem with this approach is that it often results in an amateurish Web site that is not useful, usable, or desirable. Technology-centered Web sites were pervasive in the early days of the Web, but thankfully they are becoming less common as the Web matures. Designer-Centered Design Designer-centered design (also known as ego-centered design) is still popular in certain circles. One designer was quoted in a popular industry rag as saying, What the client sometimes doesnt understand is the less they talk to us, the better it is. We know whats best. This is exactly what we mean by designer-centered design. Dont get us wrong, though. Some design teams have deep-seated creative urges that are matched only by their incredible technical ability. They can create sites that are cool, edgy, and loaded with the latest technologies. Sometimes this is exactly the image a company wants to project. Unfortunately, such sites can also be slow to download and hard to use, and they may not work in all Web browsers. Designer-centered design is fine for some art Web sites, but not for e-commerce or informational sites whose livelihood depends on a large number of repeat visitors. The Advantages of Customer-Centered Design In company-centered design, designers give no thought to why people would visit the companys Web site and what they would want to do there. In technology-centered design, technology is an end rather than a means of accomplishing an end. In designer-centered design, the needs of other people are given less importance than the creative and expressive needs of the design team. Contrast these styles with customer-centered design, which emphasizes customers and their tasks above all, and sees technology as a tool that can empower people. Company-centered, technology-centered, and designer-centered design styles were understandable in the early days of the Web, when designers were still finding their way. In the old worldview, few people really considered what customers wanted. Now, successful and easy-to-use sites like amazon.com, yahoo.com, flickr.com, and ebay.com are designed from the ground up to meet the needs of their customers. In the new worldview, your careful consideration of customers, as reflected in your Web site, will help you achieve long-lasting success.

Foundations of Web Site Design

11

Customer-Centered Web Design: More Than a Good Idea

Top Ten Signs That Things Are Going Badly


1. Customers? Our Web site is already intuitive and user-friendly. 2. We need to start doing some usability tests before our launch next month. 3. We can use [XML/SOAP/insert other buzzword technology] to fix that. 4. If you stop and think about how the interface works for a second, it makes complete sense. 5. How can our customers be so stupid? Its so obvious! 6. Well, they should read the fantastic manual. 7. We dont need to do any user testing. Im a user, and I find it easy to use. 8. Well just put an Under Construction sign there. 9. Shrink the fonts more so that we can put more content at the top. 10. We need a splash screen.

Nine Myths of Customer-Centered Design


Why are there so many organizations that do not embrace customercentered design? In this section we will try to dispel the myths that keep companies from moving forward with customer-centered design. Myth 1: Good Design Is Just Common Sense If Web site design is just common sense, why are there so many bad Web sites? Thinking that design is just common sense leads us to think that we know what everyone needs and wants. Time and time again, however, this notion has been shown to be incorrect. Web design teams always have to keep in mind that they are not the customers. They cannot always predict the way customers will think or act. In addition, they know too much about how the Web site works. They cannot look at it in the same way that customers will. They can avoid this problem by observing and talking to customers and getting feedback from them as often as possible. Myth 2: Only Experts Create Good Designs Although experts might apply customer-centered design techniques more quickly or conduct more rigorous analyses, anyone can understand and

1.5

12

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

use these techniques. Anyone devoted to the process can create a good design. Myth 3: Web Interfaces Can Be Redesigned Right before Launch Sentiments like well spend a few days working on our sites interface or well solve the interface problems after all the programming is done are common. However, these ideas assume that the Web site has the right features and that those features are being built correctly. These are two very risky assumptions that can be costly to fix, especially if the Web site is near completion. Customer-centered design helps minimize these risks by getting constant feedback on designs so that the Web site will be in good shape the day it is launched. Myth 4: Good Design Takes Too Long and Costs Too Much Customer-centered design does add some up-front costs because you will be talking to customers, creating prototypes, getting feedback on those prototypes, and so on. However, customer-centered design can considerably reduce back-end coststhat is, costs incurred as a result of responding to customer dissatisfaction through help desk calls, returned purchases, general Web site maintenance, and so on. Evaluate the trade-off between spending more time and money at the start of your project and losing revenue over the long run. Customer-centered design can even reduce the total development time and cost because it focuses on finding problems in the early stages of design when they are still easy to repair, preventing them from ever causing serious problems that are time-consuming and expensive to fix. Of course, your team will not always have the time and budget to do everything possible, so throughout this text we try to identify the trade-offs among the different actions you can take to improve your site. This book discusses many effective approaches that you can use to test your assumptions and to test your Web site, to make sure that it is a winner in the long run. Myth 5: Good Design Is Just Cool Graphics An aesthetically pleasing design is an important part of any Web site because it helps communicate how to use a particular interface and it conveys a certain impression. However, graphics are only one part of the larger picture of what to communicate and how. Customer-centered design takes into account what customers want, what they understand, the tasks they perform, and the context in which they do things. Cool graphics by themselves do not address these issues.

Foundations of Web Site Design

13

Customer-Centered Web Design: More Than a Good Idea

Myth 6: Web Interface Guidelines Will Guide You to Good Designs Web interface guidelines are a good checklist to ensure that the final design has no obvious minor problems. However, guidelines address only how a Web site is implemented. They do not address what features a Web site should have, the overall organization of the Web site, or the flow between individual Web pages. In contrast, the design patterns described in this book are generative. Using them will help you create solutions to your design problems. Furthermore, guidelines do not address the trade-offs of Web site development. Customer-centered principles, processes, and patterns, on the other hand, do take these issues into account. Myth 7: Customers Can Always Rely on Documentation and Help Documentation and help are important, but customers are unlikely to be patient enough to sift through a great deal of documentation just to use a Web site. Documentation and help are the last resorts of a frustrated customer. Think about it this way: When was the last time you read a help page? Did you wish the design team had gone the extra mile in the first place to make using the site straightforward so that you would not need to read the help? Customer-centered design provides tools to see the world from your customers eyes, to help you understand their worldview, and then to design Web sites to fit their needs. Myth 8: Market Research Reveals All Customer Needs Although market research is invaluable for helping to understand customer attitudes and intentions, it does not suffice when it comes to understanding customer behavior. Be careful also about using market research to create lists of customer feature requests. Implementing a laundry list of new features might satisfy customers who have asked for a particular feature, but all these features are more likely to get in the way of offering most of your customers a satisfying and successful customer experience. What customers say in a market research study can be useful, but when it comes to interfaces, what they do is critical. Thats why market research must be balanced with direct observation. A customer-centered design team uses a variety of techniquesfrom observations to interviews to elicit true customer needs and focus on the areas that will be the most important for most customers. Myth 9: Quality Assurance Groups Ensure That Web Sites Work Well Software testing is key to ensuring that you are not launching a buggy, poorly performing site. Although quality assurance is important, its purpose

14

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

and focus are different from those of customer-centered design. Software testing is often technology driven rather than customer driven. Expert testers try to make sure the product does what the specification says it should. This is different from seeing what happens with real customers working on real problems. More importantly, Web sites often are tested only after being built. At that point its too late to make major changes. Software testing can help you find and fix only coding mistakes, not major design mistakes. Customercentered design, in contrast, focuses on quality from the very startbefore anyone has written a line of code.

1.6 Applying Customer-Centered Design


Over time we have evaluated the best practices to use when designing powerful, compelling, and useful interactive Web sites. We realize that designers need concepts that they can quickly integrate into their Web site design practices, as well as a process that can be applied universally, from entertainment sites to e-commerce sites, from sites for informal clubs to sites for large corporations. Our experiences, research, and discussions with other Web designers have helped us refine our ideas on customercentered design into three parts: principles, processes, and patterns. Principles Principles are high-level concepts that guide the entire design process and help you stay focused. For example, as we state in one of our key principles, you must acquire a deep understanding of your customers needs. Another major principle is to design your Web site iteratively, moving from rough cuts to refined prototypes, before creating the production Web site. These principlesdescribed in Chapters 3 (Knowing Your Customers: Principles and Techniques) and 4 (Involving Customers with Iterative Design)can be applied to any design problem and are the foundation for the patterns that we describe in the second half of the book. Processes Processes are how you put the principles into practice. In Chapter 5 (Processes for Developing Customer-Centered Sites), we describe our Web site development process, providing a guide that explains the major steps and milestones for developing a Web site. We also provide a collection of how-to tips, such as how to conduct a focus group, how to run a survey, and how to conduct a usability test (most of these tips are included

3 4

Foundations of Web Site Design

15

Customer-Centered Web Design: More Than a Good Idea

in the appendixes). If your firm has similar processes, use Chapter 5 to update your process so that the key principles of customer-centered design are supported. Patterns Design patterns solve recurring design problems, so you can use pattern solutions to design your sites without reinventing the wheel. Patterns are a language, a common vocabulary that allows you and your team to articulate an infinite variety of Web designs. These patterns let you focus your energies on solving new problems, rather than addressing problems that have been worked out hundreds of times before. But design patterns do not make cookie-cutter sitesfar from it. Because no two businesses are the same, we created the design patterns for you to tailor to your particular business needs. This book shows you how to create an overall solution that works for your customers and your business. Using the Principles, Processes, and Patterns Design is about making informed trade-offs between competing constraints. Customer-centered design tries to make these trade-offs clearer, but only you can solve the problems. The principles help you decide between different process activities at a particular stage of your project. For example, in evaluating whether to iterate on a paper design one more time or to build a high-fidelity version of the design, you might decide to stick with paper because you can easily bring in potential customers to evaluate the design. You can also use the principles to help you decide among the different design solutions that you developed using the patterns. Say, for example, that youre not sure whether your branding is prominent enough during checkout on your site. You could use online surveys, a common tool of market researchers, to quickly see what potential customers think.

Take-away Ideas
Your opportunities on the Web are vast, but so are the difficulties of delivering a site that customers will give high marks for content, ease of use, performance, trustworthiness (as well as other indicators of brand value), and overall satisfaction. These problems are not insurmountable if you solve them with the set of principles, processes, and patterns that we describe in this book.

1.7

16

Foundations of Web Site Design

Customer-Centered Web Design: More Than a Good Idea

In the rest of this book you will find more reasons to implement customercentered design, descriptions of techniques to use in your current projects, and over a hundred design patterns proven to enhance your customers experience. Guidelines for instituting customer-centered design will help you through the process. This book is meant as the first step in an ongoing conversation to improve the Web. We have not identified all of the useful Web design patterns. New patterns will be found, and the patterns we describe here will evolve as new techniques are invented and customer knowledge and skills change. In fact, this second edition of the book adds 17 new patterns and includes major revisions to 25 of the existing patterns. We encourage you to join in the conversation and keep moving the Web toward the new, raised bar for success.

Foundations of Web Site Design

17

H1 PROCESS FUNNEL
Figure H1.1 Honda uses a process funnel consisting of several logical steps that guide customers to quickly configure a car with the desired options. Information in floating windows shows additional details but keeps customers in the funnel so that they can continue to completion.

H1.1

(www.automobiles.honda.com, April 27, 2006)

BACKGROUND
All Web sites that lead visitors through stepped tasksPERSONAL E-COMMERCE (A1), SELF-SERVICE GOVERNMENT (A4), WEB APPS THAT WORK (A10), and ENABLING INTRANETS (A11)need ways to help people succeed at completing the tasks.
A1 A4 A10 A11

546

Patterns: Helping Customers Complete Tasks

PROCESS FUNNEL

H1

PROBLEM
Customers often need to complete highly specific tasks on Web sites, but pages with tangential links and many questions can prevent them from carrying out these tasks successfully. People enjoy completing the tasks they start. Yet all kinds of distractions including links that lead off the critical path, extra steps, and extra content can inadvertently lead them away from accomplishing their goals. These diversions can have legitimate purposes, however, such as providing continuity, giving visitors opportunities to explore, providing instructions, or providing extra details. Striking a balance between these various forces and the actual task can be challenging. Minimize the Number of Steps Required to Complete a Task Customers find tasks daunting if there are too many steps. A process funnel might have anywhere from two to six discrete steps. Anything less than two steps is not a process, and a process of more than six steps can be unmanageable. If there are more than six steps, try to split the process into two or more separate process funnels, or try combining multiple steps on one page. You dont want to intimidate customers with too many steps. However, these are not always viable solutions, because one choice may precede another, and not every page can hold all the information that customers might need at certain points. Provide a Progress Bar to Let Customers Know Where They Are in the Process Funnel Showing a PROGRESS BAR (H13) at each step lets your customers know how much farther they need to go to complete the task (see Figure H1.2). Note that its often not worth your effort to make the individual steps on the progress bar clickable because doing so adds more

H13

Figure H1.2 Many Web sites use a progress bar like this one at Half.com to let customers know where they are in the process funnel and how much farther they have to go.

H1.2

(www.half.com, October 24, 2001)

Patterns: Helping Customers Complete Tasks

547

H1

PROCESS FUNNEL

complexity but little benefit for customers. See the PROGRESS BAR (H13) pattern for situations where it makes sense to allow this. Remove Unnecessary Links and Content While Reinforcing the Brand Removing links and content that are unrelated to the task at hand will reduce the number of distractions, making it more likely that your customers will successfully complete their tasks. Remove extraneous NAVIGATION BARS (K2), TAB ROWS (K3), LOCATION BREAD CRUMBS (K6), and EMBEDDED LINKS (K7), leaving only the links and ACTION BUTTONS (K4) that help visitors reach their goals, as well as an obvious exit that cancels the process funnel. Take out any content that is superfluous to the task. Reinforce the Web SITE BRANDING (E1) to minimize any disorientation that customers might feel from sudden changes in navigation options. Use the same fonts, images, colors, layout, and logo throughout the Web site so that, no matter where they are, people know theyre still on the same site. Use Floating Windows to Provide Extra Information, without Leading Visitors Out of the Process Funnel Sometimes customers need additional information that you have not provided on a page, such as extra help or product details. Provide a link to a FLOATING WINDOW (H6) containing CLEAN PRODUCT DETAILS (F2) (see Figure H1.1), CONTEXT-SENSITIVE HELP (H8), or information from the FREQUENTLY ASKED QUESTIONS (H7) page, to make the extra information less intrusive. Your challenge is to implement this extra content without detracting from the main purpose. Make Sure the Back Button Always Works Customers often use the Back button on browsers to modify answers that theyve typed in on previous pages. If the Web site is not implemented correctly, however, the information that theyve already entered may be lost when they hit the Back button, forcing them to type everything again. In the worst case, people get a cryptic error message saying that the posted information was lost. You can address this annoying problem by temporarily storing the information entered on each page, redisplaying this information if customers hit the Back button, and then overriding the temporarily stored information on the page if it is changed.

H13

K2 K3 K6 K7 K4

E1

H6 F2 H8 H7

548

Patterns: Helping Customers Complete Tasks

PROCESS FUNNEL

H1

K4

K5

Always Make It Clear How to Proceed to the Next Step Some Web pages are longer than can be displayed on a customers Web browser, and people sometimes get lost if the critical ACTION BUTTON (K4), the one that takes them to the next step, is hidden below the fold. Place HIGH-VISIBILITY ACTION BUTTONS (K5) both high and low on the page, ensuring that at least one of the critical action buttons will always be visible without scrolling. Allow Customers to Skip Unnecessary Steps Customers sometimes need to be able to skip unnecessary steps in a process. For example, customers do not always choose the gift-wrap option on Amazon.com during the checkout process. Some steps might automatically be skipped if the required information is automatically supplied, as when name and address information comes from a customer database, such as in SIGN-IN/NEW ACCOUNT (H2), rather than being supplied manually by a customer logging on with a GUEST ACCOUNT (H3). A step also can be skipped, for example, when customers supply a billing address and then check the Shipping Address Same as Billing Address box so that they dont have to type the whole address again. If a choice that the customer makes early in the process eliminates the need for one or more subsequent steps, then simply skip the subsequent steps in the PROGRESS BAR (H13) and treat them as if they were completed. Dont remove steps from the progress bar in the course of the process (or add them, for that matter) because this might confuse the customer. Prevent Errors and Provide Error Messages Whenever Errors Do Occur People will always make mistakes, even with the best of designs. You can help PREVENT ERRORS (K12) if you use CLEAR FORMS (H10) with structured fields, sample input, and PREDICTIVE INPUT (H11). At the same time, provide MEANINGFUL ERROR MESSAGES (K13) whenever errors do occur.

H2

H3

H13

K12 H10 H11 K13

Patterns: Helping Customers Complete Tasks

549

H1

PROCESS FUNNEL

SOLUTION
Minimize the number of steps required to complete a task, keeping them between two and six. Remove unnecessary and potentially confusing links and content from each page, while reinforcing the brand to maintain a sense of place. Use floating windows to provide extra information without leading people out of the process funnel. Make sure the Back button always works so that customers can correct errors. Use high-visibility action buttons to make it clear how to proceed to the next step. Let customers skip steps that may be unnecessary. Prevent errors where possible, and provide error messages whenever errors do occur.
Figure H1.3 A process funnel lets people complete their goals by breaking down complicated tasks into a small number of steps, using floating windows for detailed information, and including only critical links, so that people are not distracted.

H1.3

OTHER PATTERNS TO CONSIDER


Many kinds of Web sites use process funnels, including sites for PERSONAL E-COMMERCE (A1), SELF-SERVICE GOVERNMENT (A4), WEB APPS THAT WORK (A10), and ENABLING INTRANETS (A11). Customers use process funnels when they finalize purchases through QUICK-FLOW CHECKOUT (F1), when they
A1 A4 A10 A11 F1

550

Patterns: Helping Customers Complete Tasks

PROCESS FUNNEL

H1

H2 G4

K2 K3 K4 K6 K7

E1 K12 H10 K13 H13

H5

H8 H7 H6

I2 K5

create new accounts through SIGN-IN/NEW ACCOUNT (H2), and when they post new messages to a RECOMMENDATION COMMUNITY (G4), to name some examples. Remove NAVIGATION BARS (K2), TAB ROWS (K3), irrelevant ACTION BUTTONS (K4), LOCATION BREAD CRUMBS (K6), and EMBEDDED LINKS (K7) to ensure that customers stay on their paths. However, keep strong SITE BRANDING (E1) so that customers still know where they are. Design process funnels to PREVENT ERRORS (K12) by using CLEAR FORMS (H10) for each step of the process funnel and provide MEANINGFUL ERROR MESSAGES (K13) when errors do occur. Consider also adding a PROGRESS BAR (H13) that tells people where they are in the process and how much farther they have to go. Track your customers through PERSISTENT CUSTOMER SESSIONS (H5) to avoid problems with the Back button, and to save customer-entered information. Move extra content, such as CONTEXT-SENSITIVE HELP (H8) and FREQUENTLY ASKED QUESTIONS (H7), to FLOATING WINDOWS (H6) to keep the main task page on the screen. Make the next action visible by keeping it ABOVE THE FOLD (I2) and by using HIGH-VISIBILITY ACTION BUTTONS (K5).

Patterns: Helping Customers Complete Tasks

551

I S B N : 0 -321-396 8 5 - 5

B U Y TH E b OO K TO DAY

ECLIPSE WEB TOOLS PLATFORM


DEVELOPING JAVA WEB APPLICATIONS

Naci Dai Lawrence Mandel Arthur Ryman

Upper Saddle River, NJ Boston Indianapolis San Francisco New York Toronto Montreal London Munich Paris Madrid Capetown Sydney Tokyo Singapore Mexico City

CHAPTER 6
Organizing Your Development Project
All right, guys! Its time to clean up this town! Homer Simpson In this book we describe how to build applications that are defined by the J2EE specification. When you build an application, you create one or more projects that correspond to J2EE modules. You also use these same projects to organize your development work; that is, you use these projects

to manage the source code and files that make up the application, to divide the work between the teams, and to set up an automated process that builds the application, runs tests, and creates project reports.

This chapter starts with a basic description of the types of applications and projects that are supported in WTP. We will show you how to create different kinds of projects to build applications. In the second part of the chapter, we will describe some of the advanced project features that are available with WTP. There is very little available in terms of standards to guide you in the organization of project artifacts and source code for Web projects. Project best practices achieve a balance between the concerns that drive a particular development project:

How many teams and developers are there? What are the subsystems? What components are tested, and how are they tested? Who builds the code?
137

138

CHAPTER 6 Organizing Your Development Project

How is it integrated? How is it released?

Naturally, each concern is a different dimension of the project. We will use advanced WTP features to create project templates and apply best practices that are helpful to organize your development work. We use the generic term Web project to describe the WTP project types that are provided for J2EE development.

Web Project Types and J2EE Applications


A project is used to develop modules such as J2EE Web applications and EJBs. Typically, each module is a project, but this is not a strict requirement (see Figure 6.1).
Enterprise Application Project Web Project Web Project
leagueplanet.war Common League and Player Managment Subsystem

Web Project leagueplanet.war Utility Project


News and Announcements Subsystem

Utility Project
Advertising and Sponsors Subsystem

EJB Project
leagues.jar

An enterprise application project that contains a Web project and an EJB project with components for leagues and players.

For better manageability, a team can divide a large Web project into many projects. Each project is used to develop a subsystem.

Figure 6.1

J2EE Applications and Web Projects

For example, in a complete J2EE enterprise application, one project might consist of a Web application module for the presentation logic while another would be used to develop the EJB module for the business components. In this case, the complete application consists of three projects for the modules: one for the enterprise application, one for the Web application, and one for the EJBs. It is also possible to split the development of a single module into multiple projects. For example, a basic module like a Web application might be built from utility modules built in other projects. You will learn how to organize your projects and modules using similar patterns later in this chapter.

Web Project Types and J2EE Applications

139

Web Projects
Projects organize your source code and modules. WTP provides Web projects that are sophisticated Eclipse projects that know about J2EE artifacts. In addition to having basic Java project capabilities, a Web project can be used to organize J2EE artifacts into buildable, reusable units (see Figure 6.2).

Simple Project

Organizes resources Manages source code

Java Project

Understands java artifacts (.java, .class,. . .) Has Java builders Runs on a Java VM

Webtools Flexible Project


Figure 6.2 Web Projects

Understands Web artifacts (.jsp, .xml, .html,. . .) Has Web builders Understands J2EE Modules and artifacts Runs on a server

An Eclipse simple project (or general project) provides the basic infrastructure to organize and build resources. The structure of a general project is very open; resources such as files and directories can be organized in any arbitrary form that makes sense for a particular purpose. A JDT Java project contains Java elements such as packages, types, methods, fields, and property files for creating Java programs. A Java project knows how to build and run Java programs. Each Java project has a Java builder that can incrementally compile Java source files as they are edited. You can change the properties of a Java project, such as the Java build path. The build path is the classpath that is used for building the project. There are alternative ways of structuring the sources in a Java project; examples include using a single source folder that is the project root or multiple source folders for organizing complex Java projects. A WTP Web project has more than just Java code. It contains sources that are used to build Web applications, EJBs, and enterprise applications. A Web application can be as simple as a bunch of HTML files, or it can have servlets,

140

CHAPTER 6 Organizing Your Development Project

JSPs, tag libraries, and Web services. These artifacts make the Web application. A Web project knows how to build, publish, and run J2EE modules and artifacts on application servers. Web projects have builders, validators, and code generators. Builders produce standard publishable modules from complex development layouts. Validators help identify and catch coding errors at development time. J2EE validators are very valuable, because the sooner you find a problem the easier it is to fix. In J2EE, there are many deployment descriptors that have references to Java code and each other. These are interrelated in complex ways. Failure to catch a problem at development time could lead to a runtime error that might be very difficult to diagnose and fix. Generators create components from annotations in source code (for example, using XDoclet or JSR 175).

J2EE Modules
The output of the development activities are discrete J2EE components (EJBs, servlets, application clients), which are packaged with component-level deployment descriptors and assembled into J2EE modules. Web application modules, EJB modules, enterprise application modules, and Java 2 Connector Architecture (J2CA) resource modules are typical J2EE modules. A module contains code, resources, and deployment descriptors. A J2EE module forms a stand-alone unit, which can be deployed and run on a J2EE application server. Figure 6.3 provides an overview of the J2EE structure associated with common J2EE modules, such as Web, EJB, and EAR, as described by the specification.

Creating Applications
WTP provides projects and wizards to help you get started quickly with different types of Web and J2EE applications. You can use these wizards to create most standard Web and J2EE artifacts. Additional tools will help you create, build, validate, and run your applications on servers. To get started, we will review the steps involved in creating different types of applications. The simple steps provided in this section will help you acquire the skills you will need to work with the examples in this book. More specifically, you will learn how to create these types of projects:

Dynamic Web project, where the output artifact is a WAR file EJB project, where the output artifact is an EJB JAR file EJB client project, where the output artifact is a JAR file that contains client-side classes for accessing an EJB module

Web Project Types and J2EE Applications

141

Enterprise application project, where the output artifact is an EAR file containing Web, EJB, and other modules

web web-inf/ classes/ com... lib/ struts.jar ... web.xml images/ logo.gif index.jsp ...

Classes Libraries Deployment descriptors

ear meta-inf... MyBean.class ... application.xml ... league.jar news.jar leagueplanet.war console.war

Classes Deployment descriptors EJB modules Web modules

Web content

ejb com... MyBean.class ... ejb-jar.xml ... client.jar

Classes Deployment descriptors EJB client.jar

Figure 6.3

J2EE Modules

Creating Web Applications

To build a Web application you need a project that contains a Web module. There are two types of Web projects: static and dynamic. Static Web projects contain resources that provide static content. You can use a static Web project to develop Web applications that contain many of the standard Web resources, such as HTML, images, CSS, and XML, and test them using a Web browser. These projects can be deployed to a conventional Web server, such as the Apache HTTP Server, that has no J2EE capabilities. Dynamic Web projects are for J2EE Web applications that contain servlets, JSPs, and filters, in addition to static content. A dynamic Web project can be used as a stand-alone Web application, or it can be combined with other modules to create a J2EE enterprise application. The J2EE specification defines a standard for Web application directory structure. It specifies the location of static Web files, JSPs, Java class files, Java libraries, deployment descriptors, and supporting metadata. The default dynamic Web project layout resembles the structure of a J2EE Web application

142

CHAPTER 6 Organizing Your Development Project

module. In the workbench, you can use the New Web Project wizard to create a new Web project. WTP has support for other types of project layouts and can automatically build a J2EE Web application archive (WAR) structure defined by the standard. When you want to create a dynamic Web project, you will typically do the following: 1. Invoke the Dynamic Web Project wizard. 2. Provide parameters such as project name and locations for Web artifacts. 3. Choose a target runtime. 4. Choose project facets. You can try these steps by repeating the following: 1. Switch to the J2EE perspective. In the Project Explorer view, right click, and invoke the New Dynamic Web Project menu item (see Figure 6.4).

Figure 6.4

Select Wizard

Click Next. The New Dynamic Web Project wizard opens (see Figure 6.5).

Web Project Types and J2EE Applications

143

Figure 6.5

New Dynamic Web Project

2. Enter LeaguePlanetWebProject for the project name. A dynamic Web project contains J2EE components such as JSPs and servlets. It is necessary for J2EE APIs to be a part of the project classpath. This is done for you automatically when you associate a J2EE server runtime with the project. The runtime provides a set of libraries that will also contain JARs such as the servlet.jar. If you switch the runtime at a later time, the classpath is also updated. If your prefer not to use a runtime to provide these libraries, you can create a folder that contains the J2EE libraries and point to it as your runtime library. However, this method will require you to obtain appropriate libraries for the J2EE APIs from
http://java.sun.com

Assuming you have defined a server runtime such as Tomcat, select it as the target runtime. We will revisit servers and runtimes in other chapters. Configurations allow you to choose a set of project facets for common styles of Web projects. For example, if you choose the WebDoclet configuration, WTP will set up the project to enable XDoclet.

144

CHAPTER 6 Organizing Your Development Project

Click the Next button. The Project Facets selection page is displayed (see Figure 6.6).

Figure 6.6

Select Project Facets

3. A project facet describes some runtime aspect of the Web module. For Tomcat 5.0, you can specify the J2EE version, the Java version, and, optionally, the XDoclet version. Each server defines a set of supported facets and their allowed values. WTP configures the Web module and sets up the classpath for the project so that it matches the specified facets. Accept the defaults here and click the Next button. The Web Module page is displayed (see Figure 6.7). 4. The Web Module page lets you specify its context root name and the directories for its Web and Java resources. The context root is the name that appears in the URL for the Web application. Specify LeaguePlanetWebProject as the context root and accept the defaults for the directory names. Click Finish. WTP creates the project and populates it with configuration files such as the J2EE Web deployment descriptor, web.xml (see Figure 6.8).

Web Project Types and J2EE Applications

145

Figure 6.7

Web Module

You have now created a dynamic Web project named LeaguePlanetWebProject and targeted it to Tomcat. The Dynamic Web Project wizard creates folders and files under the project (see Figure 6.9). Open the project you have just created and browse its contents. For example, the WebContent folder contains a special folder named WEB-INF, which holds items that are defined by the J2EE specification and are not accessible by a Web browser. The WEB-INF/classes folder is where compiled Java code goes. It also contains a special file, web.xml, which is the J2EE Web deployment descriptor. The WebContent folder contains Web resources such as JSP and HTML files, and other types of supporting resources (see Figure 6.9). The contents of WebContent will be accessible from the Web application context root. The following default elements are created with a dynamic Web project:

WebContent/WEB-INF/web.xml: src:

This is the Web deployment descriptor.

This is the Java source code for classes, beans, and servlets. The publisher will copy the compiled class files into the WEB-INF/classes folder of the final application.

146

CHAPTER 6 Organizing Your Development Project

Figure 6.8

Dynamic Web ProjectLeaguePlanetWebProject

Project Web Module

WebContent * WEB-INF Resource * classes lib web.xml Resource *

JavaSource * Resource

Class

Figure 6.9

Elements of a Dynamic Web Project

Web Project Types and J2EE Applications

147

WebContent:

This is the Web application root. All Web artifacts placed in this folder will be available to the client. The publisher will copy the complete contents of this folder into the root of the final WAR file. It is possible to choose a different name for the WebContent folder or rename it.

Sometimes code and libraries will be delivered to you in the form of class files (in comparison to those that are provided to you as JAR files, which you would put into the WEB-IF/lib folder). To add them to the classpath of the final Web application, you can place them in this folder.
WebContent/WEB-INF/classes: WebContent/WEB-INF/lib:

We will place all libraries that are provided to use in the form of JAR files here. They will be added to the build path of the project. The publisher will copy them into the WAR file, and they will be available to the class loader of the Web application.

A dynamic Web project can publish its contents as a Java Web application archive (WAR) file (see Figure 6.10). Publishers assemble the artifacts in a Web project, such as Java sources; Web content, such as JSPs, HTML, and images; and metadata, such as Web deployment descriptors, in a form that can run on a J2EE application server.

LeaguePlanetWebProject LeaguePlanetWeb JavaSource/ com.../ LeaguesAction.java WebContent/ WEB-INF/ lib/ struts.jar ... web.xml images/ logo.gif index.jsp ... leagueplanet.war web-inf/ classes/ com... lib/ Builders struts.jar ... web.xml images/ logo.gif index.jsp ...

...

module

Development View (WTP)

Runtime View (J2EE Spec.)

Figure 6.10

Publisher

148

CHAPTER 6 Organizing Your Development Project

WTP wizards simplify the tasks involved in creating J2EE modules. We have just shown how to create a Web module. WTP online documentation at
www.eclipse.org/webtools

provides detailed information about these wizards and the project structure. The process of creating an EJB application is equally simple. The next section describes how to create an EJB project that contains an EJB module.

Creating EJB Applications


An EJB project contains an EJB module. This project can be used to assemble one or more enterprise beans in a single deployable unit. EJBs are deployed in a standard Java archive (JAR) file. An EJB project can be used to build stand-alone components, or it can be combined with other modules in a J2EE enterprise application (EAR). Recall the structure of an EJB module (see Figure 6.3 earlier). EJB modules have a simple structure that contains EJB classes and deployment descriptors. In the workbench, we can use the New EJB Project wizard to create a new EJB project with an EJB module in it.

Getting an EJB Container EJB projects require a server runtime environment that supports EJBs. You will need an application server such as Geronimo, JBoss, or JOnAS to develop EJBs with WTP. You should obtain the application server first, and use the WTP preferences to define a new server runtime environment. You can obtain Geronimo from
http://geronimo.apache.org

or you can download and install it via WTP (see the Installing Third-Party Content section in Chapter 4). JBoss can be obtained from
http://www.jboss.org

and JOnAS can be obtained from


http://jonas.objectweb.org

You will not be able to use Apache Tomcat for EJB development. Tomcat only supports J2EE Web modules, not EJBs or enterprise applications.

Web Project Types and J2EE Applications

149

When you want to create an EJB project, you will typically do the following: 1. Switch to the J2EE perspective. In the Project Explorer view, right click, and invoke the New EJB Project menu item (see Figure 6.11).

Figure 6.11

Select Wizard

Click Next. The New EJB Project wizard opens (see Figure 6.12). Enter LeaguePlanetEJB for the project name and select a target runtime that supports EJBs such as JBoss. We will discuss EJBs in more detail later in Chapter 8. Configurations allow you to choose a set of project facets for common styles of EJB projects. For example, if you choose the EJB Project with XDoclet configuration, WTP will set up the project to enable XDoclet. Click the Next button to proceed to the Project Facets selections page. 2. Project facets describe aspects of J2EE modules (see Figure 6.13). For an EJB module, you can specify the J2EE version, the Java version, and, optionally, the XDoclet version. Each server defines a set of supported facets and their allowed values. For example, you will not be able to set an

Figure 6.12

New EJB Project

Figure 6.13

EJB Project Facets

150

Web Project Types and J2EE Applications

151

EJB facet using a Tomcat server because it does not have an EJB container. WTP configures the EJB module and sets up the classpath for the project so that it matches the specified facets. Here, you will use XDoclet to develop EJBs. Add the XDoclet facet by checking it. Accept the defaults for the EJB and Java facets and click the Next button to proceed to the EJB module settings. 3. The EJB Module page (see Figure 6.14) lets you specify the directory for Java resources. Optionally, you can create a Java utility module that will contain EJB classes and interfaces, which will be required by EJB clients. Click Finish.

Figure 6.14

EJB Module

4. WTP creates the EJB project and populates it with configuration files such as the EJB deployment descriptor, ejb-jar.xml (see Figure 6.15). You may notice some errors in the new EJB project. For example, if your EJB project does not contain any EJB components, this is considered an error according to the J2EE specification. If you chose the XDoclet facet and an XDoclet runtime is

152

CHAPTER 6 Organizing Your Development Project

not yet configured, this will show up in the problem markers. These errors are normal and will be removed when you fix the preferences and add EJBs to the project.

Figure 6.15

Project ExplorerEJB Project

The ejbModule folder contains Java and EJB resources such as the deployment descriptor (see Figure 6.16). Similar to Web application modules, an EJB project has a publisher for EJB applications (see Figure 6.17). This publisher creates a deployable EJB module from the contents of the project with all the classes and deployment descriptors. EJB Client Projects There is another EJB related project type called the EJB Client Project.These projects are used to share common classes between EJB modules and their clients such as a Web application.Typical classes that are found in these modules are the EJB interface types and models. EJB project wizards can create an EJB client project.This option can be selected only when the EJB module is added to an EAR module. It is also possible to add the client project to an existing EJB module by using the context menu in the Project Explorer view.

Web Project Types and J2EE Applications

153

Project

EJB Module

ejbModule

* META-INF Resource

* Class

* ejb-jar.xml Resource

Figure 6.16

Elements of an EJB Project

LeaguePlanetEJBProject LeagueBeans ejbModule/ com.../ LeagueBean.java PlayerBean.java ... META-INF/ ejb-jar.xml ... module ... Builders LeagueBeans.jar meta-inf/ ejb-jar.xml com... ...

Development View (WTP)

Runtime View (J2EE Spec.)

Figure 6.17

EJB Publisher

154

CHAPTER 6 Organizing Your Development Project

This completes the process of creating an EJB project. The next section describes how to create an enterprise application project that can combine EJB and Web modules in a J2EE Enterprise Application (EAR) module.

Creating Enterprise Applications


The most interesting J2EE enterprise applications have more than one module. They have several Web applications and EJB modules. The J2EE specification provides a basic application packaging structure called an enterprise application. Enterprise application archives are packaged as Java archives with the .ear suffix. Therefore, they are also known as EARs. An EAR can contain one or more

EJB modules Web application modules J2CA resource adapter modules Application client modules

An enterprise application project contains the hierarchy of resources that are required to deploy these modules as a J2EE enterprise application. An enterprise application module contains a set of references to the other J2EE modules that are combined to compose an EAR. In addition to the modules, an enterprise application module also includes a deployment descriptor, application.xml. Publishers for enterprise application projects consume the output of the publishers from their component modules (see Figure 6.18). For example, the builder of an EAR that contains a Web application module and an EJB module waits until the builder for the Web and EJB projects creates the deployable structures for these modules, and then it assembles these artifacts in the EAR. WTP has wizards and tools to create and edit EARs. They are described in the following use cases.
Create a New Web or EJB Module in an EAR

When a new J2EE module project is created, such as a dynamic Web project or an EJB project, it can be associated with an enterprise application project (see Figure 6.19). The project wizards let you specify a new or existing enterprise application. You can also choose the project in which you would create the enterprise application module. Finally, the EAR is updated to include the new J2EE module in it.

Web Project Types and J2EE Applications

155

LeagueApplicationProject LeagueApplication META-INF/ application.xml module

ear Builders

LeagueWebProject module Builders

war

LeagueEJBProject module
Development View (WTP)

jar Builders

Runtime View (J2EE Spec.)

Figure 6.18

EAR Publisher

Adding Existing Web and EJB Modules to an EAR

In the second scenario there are existing J2EE modules, which are to be added to a new enterprise application. You create a new EAR project and add your existing modules to it. The Enterprise Application wizard creates a new project and allows you to choose the modules to be included in it. When you want to create an EAR project, you will typically do the following: 1. Switch to the J2EE perspective. In the Project Explorer view, right click, and invoke the New Enterprise Application Project menu item (see Figure 6.20). 2. Click Next. The New Enterprise Application Project wizard opens (see Figure 6.21). 3. Enter LeaguePlanetEar for the Project name. Click the Next button to proceed to the Project Facets selection page.

Figure 6.19

Adding a Module to an EAR

Figure 6.20

Select Wizard

156

Web Project Types and J2EE Applications

157

Figure 6.21

New Ear Project

4. Project facets describe aspects of enterprise applications (see Figure 6.22). For the EAR module, there is only the EAR facet. Each server defines a set of supported facets and their allowed values. For example, you will not be able to set an EAR facet using a Tomcat server because it does not support EARs. Click the Next button to proceed to the EAR module settings. 5. The J2EE Module page (see Figure 6.23) lets you select the modules that will be included in the application. Select the LeaguePlanetEJB and LeaguePlanetWebProject modules. Note that you can also make the wizard generate new empty modules by clicking the New Modules button. Click Finish. 6. WTP creates the EAR project and its deployment descriptor, application.xml (see Figure 6.24).

Figure 6.22

EAR Project Facets

Figure 6.23

J2EE Modules

158

Web Project Types and J2EE Applications

159

Figure 6.24

Project ExplorerEAR Project

Editing EARs

In the final scenario, you modify the modules in an EAR. You can add new modules to an EAR or remove existing ones by using the J2EE Module Dependencies property page. When you want to modify an EAR project, you will typically do the following: In the Project Explorer, highlight the enterprise application LeaguePlanetEar, right click, and select Properties. As Figure 6.25 shows, you can then choose the modules to be included in the EAR. EAR modules have a simple structure. When modules are added or removed from an EAR, WTP automatically updates the module and the contents of the EAR deployment descriptor, application.xml, which is stored in the META-INF directory.

160

CHAPTER 6 Organizing Your Development Project

Figure 6.25

J2EE Module Dependencies

Advanced Web Projects


The default project types and layouts cover many of the common application and development needs. Sometimes you need to do more with a Web project; you can use it to improve your development process, organize your code, and share your work with other team members. Here are some development considerations that can determine the organization of a project:

Project Deliverables: These are the concrete outputs of the development activities. For example, in a J2EE development project, deliverables are the standard modules such as Web application archives (WARs), EJB component archives (JARs), Enterprise application archives (EARs), and so forth. Architecture also influences the design of deliverables. You may use a single EAR project if all the containers run on the same application server. However, it will be better to divide the projects if the Web and EJB containers are on different servers. Some projects are simple Web applications while others involve multiple modules and components. An application may group many Web applications and EJBs together. The J2EE specification describes a structure for these deliverables.

Advanced Web Projects

161

Team Organization: Team organization determines who will do what in the project. A team can be one person or it can have groups of developers. The structure of the project is a significant factor in determining the productivity of the team and the management of the overall software engineering process. Change Control, Configuration and Release Management: Software can be viewed in terms of components that are assembled and configured to form an application. It is important to track the changes to these components using a version control system. The organization of these components determines the units that are used to control the changes in the scope of the project. The configuration and version of components that make an application are very important to the release process. Testing: Test plans, test cases, and execution of the tests must be regular and continuous parts of the development process. Test objectives and responsibilities are determined based on the modules. Unit and integration tests are part of the development for each module.

When the WTP project was started, the development team had long discussions on how to extend the basic Java projects to handle different styles of custom projects. A key requirement for Web projects was to enable the separation of the two fundamental view points to help manage resources in a project, for example, the developer view and the runtime view. The runtime view is defined by the J2EE specification. The developers view is most often modeled using the J2EE specification. Mimicking the structures defined in the specification creates valid J2EE applications, but this is not always suitable for all development projects. In WTP, the developers view of a project is captured by a model that maps the contents of the project to the runtime view. Each WTP Web project has a structural model that is used to describe how developers lay out the resources. Publishers and WTP tools use the structural model to create J2EE artifacts. This mapping gives you flexibility to create projects in ways that you could not do before. For that reason, WTP developers sometimes also refer to these projects as flexible projects. Well use the term Web project in this book. Technically speaking, an Eclipse project that has the Module Core Nature is a Web project. This nature indicates that these projects have a structural model for the modules and will support WTP tools. We will start with a short description of this advanced project capability, and then give examples demonstrating its use. Power users can employ these capabilities to create many different layouts for their projects.

162

CHAPTER 6 Organizing Your Development Project

Modeling the Developer View


The structural model of a Web project tells publishers how to compose a runtime artifact (see Figure 6.26).

Project module
Deployable Module Builder

war

Runtime module
structural model .settings/org.eclipse.wst. common.component

Figure 6.26

Structural Model

This model is defined in an XML component file stored with the other project settings. The project settings and component files are normally invisible in the Project Explorer view. However, they are visible in the Eclipse Navigator view that is included in the Resource perspective. The structural model is stored in a file named
org.eclipse.wst.common.component

inside the .settings folder of any Web project (see Figure 6.27). The model file listed in Example 6.1 is for a typical dynamic Web application module. The module is named LeaguePlanetWebProject. The model specifies how resources in the development view map to resources in the runtime view. Here, you map the complete contents of the WebContent folder to the module root. The source-path is relative to the project root and the deploy-path is relative to the module root at the destination. You can have as many resource mappings as you like for each module. The module also has type-specific properties such as context root, which defines the context root of the Web application module. The java-outputpath property tells the publisher where to find the compiled classes.
Example 6.1 Web Module Definition
<?xml version="1.0" encoding="UTF-8"?> <project-modules id="moduleCoreId" project-version="1.5.0"> <wb-module deploy-name="LeaguePlanetWebProject">

Advanced Web Projects

163

<wb-resource source-path="/WebContent" deploy-path="/"/> <wb-resource source-path="/src" deploy-path="/WEB-INF/classes"/> <property name="context-root" value="LeaguePlanetWebProject"/> <property name="java-output-path" value="build/classes"/> </wb-module> </project-modules>

Figure 6.27

Structural Model Definition

Another example is the model of an enterprise application (see Example 6.2). Here the interesting parts are the dependent modules. In this example, the EAR uses an EJB module and a Web module. A dependent module is referenced using a handle, which is a module URL. A module URL starts with the prefix module:, and is followed by a workspace-relative path to determine the project and the name of the module within that project.
Example 6.2 EAR Module Definition
<?xml version="1.0" encoding="UTF-8"?> <project-modules id="moduleCoreId" project-version="1.5.0"> <wb-module deploy-name="LeaguePlanetEar"> <wb-resource source-path="/EarContent" deploy-path="/" /> <dependent-module deploy-path="/" handle="module:/resource/LeaguePlanetEJB/LeaguePlanetEJB"> <dependent-object>EjbModule_1147426182270</dependent-object>

164

CHAPTER 6 Organizing Your Development Project

<dependency-type>uses</dependency-type> </dependent-module> <dependent-module deploy-path="/" handle="module:/resource/LeaguePlanetWebProject/LeaguePlanetWebProject"> <dependent-object>WebModule_1147426182290</dependent-object> <dependency-type>uses</dependency-type> </dependent-module> </wb-module> </project-modules>

The structural model is a mapping for the organization of files that are distributed over a set of Web projects. A publisher uses this model and can construct a deployable, runtime Web artifact as described in the J2EE specification. When you create projects and modules using a project creation wizard, the model is automatically added to a project. Wizards create a model based on a default template. However, you can easily modify the default mapping as shown in the next sections. Some of the common types of artifacts used in model definitions are resources, modules, and dependent modules.
Resource

A resource is an abstraction of project artifacts such as files, folders, and libraries. An Eclipse project maintains its resources, ensuring that each resource is loaded only once within the workspace. Resources are referenced with resource URIs, which are relative to the projects that contain the resource. WTP has additional URI converters that can resolve URIs to their underlying physical resource, such as the module URI we discussed earlier.
Module

A module represents a deployable artifact, such as a WAR, EJB JAR, or EAR. A WTP project can be associated with only one module, but it can refer to others. This makes it possible to distribute the code for a module over a set of projects. A J2EE module has a standard layout and is targeted to some J2EE runtime container. J2EE projects generate archives as JARs or as exploded archives. These archives must contain compulsory files, such as deployment descriptors, and must conform to the J2EE specification. There are five core types of J2EE modules and a general-purpose utility module:

Enterprise application (EAR) Enterprise application client (JAR) Enterprise JavaBean (JAR) Web application (WAR)

Example Projects

165

Resource adapter for J2CA (RAR) Utility modules (JAR)

Dependent Module

As its name suggests, a dependent module is used to define dependencies between modules. It can also help define a module with its code split into several projects. For example, we can maintain the Web applications that are in an enterprise application as dependent modules. Another common pattern is to maintain basic utility JAR modules, which contain the extracted contents of the archive, as separate projects. The benefit of using extracted modules is that all the artifacts can be modified, and Web projects assemble them into a deployable form.

Example Projects
It is time to discover how you can create some interesting projects. These best practices provide different styles of projects for Web and J2EE development. You can extend and customize these examples to fit your needs. The examples well discuss are a basic enterprise application, dividing a Web module into multiple projects, and using Maven for Web application development.

Basic Enterprise Application


Using the J2EE application deployment specification as a template, you will create an enterprise application with multiple modules. This is recommended if you do not have a compelling reason to do it another way. These projects map to the J2EE specification in a straightforward way and can be created using wizard defaults. Adherence to standards reduces the behavioral discrepancies between the runtime and the development environments. In this example, each architectural application layer will correspond to a project. For example, the presentation layers will correspond to a dynamic Web project with a Web application module and the business logic layer to an EJB project with an EJB module. The enterprise application project will be used to assemble the modules as a single coherent unit. To create this structure, you will use a J2EE Enterprise Application Project (see Figure 6.28). The EAR project has two modules: LeaguePlanetWebProject, a Web application module; and LeaguePlanetEJBProject, an EJB module. The Web application module is going to be a dynamic Web project with the same name. The EJB module is divided into an EJB project and the EJB client project. The EJB client JAR is a Java utility project named LeaguePlanetEJBClientProject.

166

CHAPTER 6 Organizing Your Development Project

LeaguePlanetEar LeaguePlanetEar META-INF/ application.xml

Enterprise application module


uses uses LeaguePlanetWebProject LeaguePlanetWebProject JavaSource/ com.../ LeaguesAction.java WebContent/ WEB-INF/ lib/ struts.jar ... web.xml struts-config.xml images/ logo.gif leagues/ list.jsp index.jsp ... EJB module uses LeaguePlanetEJBClientProject LeaguePlanetEJBClientProject ejbModule/ com.../ League.java Player.java ...Home.java EJB client module uses

LeaguePlanetEJBProject LeaguePlanetEJBProject ejbModule/ com.../

LeagueBean.java PlayerBean.java
... META-INF/ ejb-jar.xml ...

Web module

Figure 6.28

Module Dependencies for League Planet Application

To demonstrate the use of Web application libraries, the Web application will use the Struts MVC framework. In order to use Struts, all Struts and supporting libraries, that is, struts*.jar, commons*.jar, jakarta*.jar, log4j.jar, and antlr.jar, are kept in the WEB-INF/lib directory. The Struts configuration file, struts-config.xml, is in the WEB-INF directory. The business model for League Planet is provided by the EJBs. The Web application delegates the business behavior to this layer.

Clean Workspace In the first part of this chapter, we described how you can create different types of projects. In this example we will use the same names. If you have tried the earlier examples and are using the same workspace, you should delete those projects before starting this one. If you would like to keep the old work, remember to back up.

Example Projects

167

To create an EAR project with this structure, do the following: 1. Start as we described earlier in this chapter to create a new Enterprise Application Project. Name it LeaguePlanetEar. Select the default facets, continue to the J2EE Modules page, and click Finish to create an empty EAR. In the next steps you will create the Web and EJB projects. 2. Repeat the steps we described earlier in this chapter to create a new Dynamic Web Project. Name it LeaguePlanetWebProject. Choose the LeaguePlanetEar as the EAR for the Web project (see Figure 6.29). Continue to the other pages to select the default facets, and click Finish to create the Web project. The EAR project will be automatically updated to reflect the addition of the new Web module.

Figure 6.29

Web Project Added to an EAR

3. To do this step, you must have the Struts framework installed someplace on your machine. You can obtain Struts from
http://struts.apache.org

168

CHAPTER 6 Organizing Your Development Project

Import all the Struts libraries and their supporting libraries into
WebContent/WEB-INF/lib

Refer to the Struts documentation for the exact list of libraries. Once the JARs are copied into the lib folder, they will be automatically added to the build path under the Web App Libraries category (see Figure 6.30).

Figure 6.30

Web App Library

4. Repeat the steps we described earlier in this chapter to create a new EJB project. Name it LeaguePlanetEJBProject. Choose the LeaguePlanetEar as the EAR for the EJB project (see Figure 6.31). You can choose one of the default facet configurations for development, such as the EJB Project with XDoclet. You do not need to change the default choices. If you do choose one, you should make sure that your workspace is set up to use it (that is, the XDoclet settings are valid). Click Next to go to the other pages to select the default facets. Click Next to go to the EJB Module page. 5. The Web application will be a client of the EJB module. Create an EJB client module named LeaguePlanetEJBClientProject (see Figure 6.32). Click Finish to create the EJB and EJB client projects. The EAR project will be automatically updated to reflect the addition of the two new modules.

Figure 6.31

EJB Project Added to an EAR

Figure 6.32

EJB Client Module

169

170

CHAPTER 6 Organizing Your Development Project

6. WTP updates the EAR project and the deployment descriptor, application.xml (see Figure 6.33).

Figure 6.33

Project ExplorerEAR Project

To create these projects, you used the same wizards described earlier in this chapter.

Web Application Module Uses EJB Client You need to make sure that the dependency between the Web application module and the EJB client is set.The Web application is a client of the EJB module.You need to describe this dependency. Remember that you created an EJB client module named LeaguePlanetEJBClientProject. You will add this module to the J2EE dependencies in the Web project. Select the Web project in the Project Explorer, right click and invoke the Properties menu item. Select the J2EE Dependencies page. In this tab, select LeaguePlanetEJBClient from the list (see Figure 6.34).

Example Projects

171

Figure 6.34

Dependency to EJB Client Module

Later, you can extend this model by adding more Web projectsan administration site, for example. The business model can be extended with more EJBs.

Dividing a Web Module into Multiple Projects


Size, structure, and the geographical and sociological aspects of a development team are significant factors in determining the project layout. When these are important to a project, they can determine the structure. The key constraints for this template are the manageability and divisibility of work. Manageability relates to aspects such as ownership of code, development responsibilities and tasks, configuration and version control, integration, and release management. Divisibility relates to dividing the work between members of the development team. In this example, you will extend the project structure described in the previous example. LeaguePlanetWebProject is a large Web application module. It will

172

CHAPTER 6 Organizing Your Development Project

contain many large, loosely coupled subsystems. League management, player management, sponsorship, and advertising are some of these subsystems that will be developed by different teams. You will divide and manage subsystems as separate projects. Each subsystem can be released on different schedules. You will therefore start by dividing the Web module into two projects (see Figure 6.35). You can increase the number of subsystems following the same pattern later on. The dynamic Web project in the previous example contains the Web application module and will have common Web components such as menus, navigation bars, and so forth. There is a new subsystem for league management. This is a Java utility project on steroids. The league management module has its own presentation layer with JSPs and Struts configuration files in addition to its own Java classes. To create this structure, you will need to create a new basic Java Utility Project named LeaguePlanetManagementWebProject. Java utility projects can be used to refactor reusable components of applications into separate projects. J2EE module dependencies will help assemble these components automatically. To create the Java Utility Project and divide the module, the following steps must be performed:

EAR

LeaguePlanetWebProject

module Team D uses Team A

EJB

uses

Web

module uses

module

changed to

LeagueManagementSubProject

EJB client

us es

module

Team B

Web module

Team C

Figure 6.35

Dividing a Web Module into Multiple Projects

Example Projects

173

1. Create a new Java Utility Project using the wizard. 2. Add the Web application libraries to its build path. 3. Add the utility project to the list of J2EE dependencies for the Web project. 4. Create a new WebContent folder in the utility project and add this to the structural model. Do the following: 1. In the Project Explorer view, right click and invoke the New menu item (see Figure 6.36). Select Utility Project.

Other

J2EE

Figure 6.36

Select Wizard

Click Next. The New Java Utility Project wizard opens (see Figure 6.37). 2. Enter LeaguePlanetManagementWebProject for the project name. Use the same target runtime for all your projects. Use the default configuration. Click the Next button. The Project Facets selection page is displayed (see Figure 6.38). Accept the defaults here and click Finish. WTP creates the empty utility project.

Figure 6.37

New Java Utility Project

Figure 6.38

Select Project Facets

174

Example Projects

175

3. You need to add this submodule to the J2EE dependencies of the Web project. To do this, select LeaguePlanetWebProject in the Project Explorer, right click, and invoke the Properties menu item. Select the J2EE Dependencies page. In this page, go the Web Libraries tab and add LeaguePlanetManagementWebProject from the list (see Figure 6.39).

Figure 6.39

Web Project Depends on Utility Project

Managing the Web Application Classpath When you add a dependency to a utility project, it is automatically added to the final WAR and to the Web App Libraries section of the build path of the Web project. However, the reverse is not true. The utility project has no knowledge of the Web application. If you have dependencies to external libraries, like Struts, in the original Web module, all JARs that are inside the WEB-INF/lib are available in the class loader of LeaguePlanetWebProject.

176

CHAPTER 6 Organizing Your Development Project

However, things can get a bit complicated if your new utility project needs classes from the Web application. For example, you may want to add new Struts actions to the utility project module or use Struts taglibs in the JSP files. You can try to add LeaguePlanetWebProject to the build path of the utility project but this would create a circularity, so Eclipse will not allow it. The best solution is to create other utility projects for common subsystems. These common utility projects can be added to the build path of the Web application as J2EE module dependencies and can also be included in the build path of the other utility projects as Java project dependencies.This approach avoids circularities. Finally, some development teams prefer to maintain the binaries for external libraries, such as Struts or Hibernate, in a common folder but not in the Web project. For example, some use Maven repositories to maintain project dependencies to these JARs.You will learn about Maven in the next section. WTP allows you to maintain libraries externally and automatically assembles them into the final WAR file before publishing it to the server. If these libraries are added as J2EE dependencies, they are also automatically added to the build path.You can use the project Properties window and add them as an external JAR dependency on the J2EE Module Dependencies tab.

4. This is an optional step. The league management module is a part of the Web module, but it may need some external libraries to be on its build path. You can do this by adding the external JARs to the build path of the Java utility project. Select LeaguePlanetManagementWebProject in the Project Explorer, right click, and invoke the Properties menu item. Select the Java Build Path page. Click on the Libraries tab. In this tab, click Add External JARs (see Figure 6.40). The JAR Selection wizard will open (see Figure 6.41). This wizard allows you to browse your local file system for JARs. Select all the same external libraries, like Struts, that you have used for the Web project here, too. Click Finish. Apply and close the Properties window. 5. Next you will create a new WebContent folder in the league management project. In the Project Explorer, select LeaguePlanetManagementWebProject, right click, and invoke the File New Folder menu item. The New Folder wizard will open (see Figure 6.42). 6. Enter WebContent as the folder name. Repeat the same process to create a new WEB-INF folder inside the WebContent folder.

Example Projects

177

Figure 6.40

Utility Project Java Build Path

Figure 6.41

Add External JARs Library

178

CHAPTER 6 Organizing Your Development Project

Figure 6.42

WebContent Folder

7. Next you will link the new WebContent folder to the main Web project and add it to the structural model so that publishers will assemble the contents of the WebContent folder from the league management project into the overall project. In the Project Explorer, select LeaguePlanetWebProject, right click, and invoke File New Folder. The New Folder wizard will open (see Figure 6.43). 8. Enter Management as the folder name. Click on Link to folder in the file system. Click Browse to select the WebContent folder created in the previous step. You will need to specify that the WebContent folder in gets copied into the deployable Web application module. Currently, there are no nice graphical tools to map these resources, so you will need to edit some files. You need to create the link to the WebContent folder before editing the module definition file. You already completed this step. Therefore, you can modify the XML component file to specify that this content folder is to be published with the Web module. This involves manually editing the
LeagueManagementWebProject
org.eclipse.wst.common.component

definition in the .settings folder. Edit the file as shown in Example 6.3.

Example Projects

179

Figure 6.43

Link to Management WebContent Folder

Example 6.3 Modified Web Module Definition


<?xml version="1.0" encoding="UTF-8"?> <project-modules id="moduleCoreId" project-version="1.5.0"> <wb-module deploy-name="LeaguePlanetWebProject"> <wb-resource source-path="/WebContent" deploy-path="/" /> <wb-resource source-path="/Management" deploy-path="/" /> <wb-resource source-path="/src" deploy-path="/WEB-INF/classes" /> <dependent-module deploy-path="/" handle="module:/resource/LeaguePlanetEJBProject/ LeaguePlanetEJBProject"> <dependency-type>uses</dependency-type> </dependent-module> <dependent-module deploy-path="/WEB-INF/lib" handle="module:/resource/LeaguePlanetManagementWebProject/ LeaguePlanetManagementWebProject"> <dependency-type>uses</dependency-type> </dependent-module> <property name="context-root" value="LeaguePlanetWebProject" /> <property name="java-output-path" value="build/classes" /> </wb-module> </project-modules>

180

CHAPTER 6 Organizing Your Development Project

You have now split a Web module into multiple projects. The publisher will add the Java classes developed in the league management project as a JAR in the WEB-INF/lib folder to the original Web application module. The publisher will also assemble any JSPs and additional Struts configuration files from the league management module, as well as all the Web content in this submodule. This content will be deployed with the Web application automatically. After the WAR is created, it will be assembled into the enterprise application as usual. When you are done, the workbench will have projects that look like Figure 6.44.

Figure 6.44

Dependent Module in the Project Explorer

Using Maven for Web Application Development


Maven is a software project management and comprehension tool. It started as a tool developed to build the Turbine project at apache.org and quickly spread to other Apache projects. Today, it is used as the main build tool for many of the

Example Projects

181

Java projects at Apache. For an in-depth description of how to use Maven on your project, refer to Maven: A Developers Notebook [Massol2005] by Vincent Massol and Timothy OBrien. Maven is more than a Java build tool. It provides capabilities to make your life easy as a developer. Some of these capabilities are a well-defined project structure, a well-defined development process to follow, and a coherent body of documentation that keeps developers and users informed of whats happening in the project. This is essential in many team projects where there arent enough people dedicated to the task of building, documenting, and propagating the information about the project. Maven captures the knowledge embedded in peoples heads to do these tasks. For example, the development processes of Eclipse and Apache are evolutionary and resulted from the experiences gained from running many projects. This body of knowledge is typically captured in the tools that are used in building projects. Maven provides a standard environment that encourages the use of development and project best practices, and it disseminates this information to project stakeholders. Following the success of Maven in Apache projects, many teams adopted Maven for their own use, including some J2EE projects. There is a set of J2EE-specific development best practices and processes captured in Maven. The use of Maven to develop a J2EE project enables the transfer of this knowledge. When a new J2EE project starts, it can immediately copy the build tasks and project know-how. The new project reuses the existing tools and conforms to the established practices. Maven does this by providing a framework and templates. For example, by having a common directory structure, developers are instantly familiar with a new project. To quote Aristotle, We are what we repeatedly do. Excellence is not an act, but a habit. There are other, less well-known approaches, such as JOFFAD, that also provide generic development frameworks to facilitate, speed up, and normalize J2EE projects. You can read about JOFFAD at
http://joffad.sourceforge.net/structure.html

In Example 6.4 you will use the advanced WTP Web project features to develop a Web application using Maven. Maven has a default, but customizable, process that gets a project started using these J2EE best practices quickly. Although both are named a project, a Maven project is conceptually very different from a WTP project. Maven and Eclipse have overlapping functionality such as compiling, building, and testing. However, Eclipse is normally used for developer-centric coding, testing, and debugging activities, whereas Maven is used for team-centric build management, reporting, and deployment. The primary purpose of Maven is to create a documented, repeatable, and modeled build process that is inclusive of all these activities. It complements the development activities in Eclipse.

182

CHAPTER 6 Organizing Your Development Project

You will start by defining a new Web project and organizing the resources in this project according to the best practices suggested by Maven. See
http://maven.apache.org/reference/conventions.html

for a description of Maven conventions. Maven recommends a standard project directory structure, which is referenced in the Maven Project Object Model (POM). The directory structure of your project will follow Maven conventions (see Example 6.4).

Manual Operation At the time of writing this book, neither WTP nor Maven had tools to create a Maven-style Web project. Therefore, you will manually prepare the project files to make WTP work with the resource structure of Maven-style projects.

Example 6.4 Maven Project Layout


/LeaguePlanetWebProject +- src/ | +- main/ | | +- java/ | | | +- ...[classes and packages] | | +- resources/ | | +- ... | | +- webapp/ | | | +- web-inf/ | | | | +- classes/ | | | | +- ...[compiled classes] | | | | +- lib/ | | | | +- ...[external libraries] | | | | +- web.xml | | | | +- ... | | | +- ...[other web files] | +- test/ | | +- java/ | | | +- ...[test classes and packages] | | +- resources/ | | +- ... | +- site/ | +- xdoc/ | +- ... +- target/ | +- ... +- pom.xml

All sources are grouped under the src directory. src/main/java contains your primary Java classes and packages. src/test/java contains your classes

Example Projects

183

and packages for unit tests. src/main/webapp, similar to the WTP WebContent folder, contains your Web content, such as the JSP and HTML files, and their supporting resources. src/site/xdoc has sources for the project Web site. To create the Maven project, do the following: 1. Repeat the steps described earlier in this chapter to create a new dynamic Web project named LeaguePlanetWebProject. Select a target runtime and default configuration for facets. Click the Next button to proceed to the Web module settings (see Figure 6.45).

Figure 6.45

Maven Web Module

2. The Web Module page lets you specify the directory for Java resources. This is where you will define locations for the Java sources and Web content. Enter src/main/webapp for Content Directory and src/main/java for Java Source Directory. Click Finish. 3. WTP creates the Web project, configuration files, deployment descriptor, and so forth. Once the project is created, the structural model for the Web project is defined as Example 6.5.

184

CHAPTER 6 Organizing Your Development Project

Example 6.5 Structural Model for Maven-Style Web Project


<?xml version="1.0" encoding="UTF-8"?> <project-modules id="moduleCoreId" project-version="1.5.0"> <wb-module deploy-name="LeaguePlanetWebProject"> <wb-resource source-path="/src/main/webapp" deploy-path="/" /> <wb-resource source-path="/src/main/java" deploy-path="/WEB-INF/classes" /> <wb-resource source-path="/src/test/java" deploy-path="/WEB-INF/classes" /> <property name="context-root" value="LeaguePlanetWebProject" /> <property name="java-output-path" value="build/classes" /> </wb-module> </project-modules>

Classpath Management with Maven and WTP WTP requires that the WebContent folder contain the J2EE specification directories WEB-INF, WEB-INF/classes for the compiled Java classes, and WEB-INF/lib for the JARs. All JARs inside this folder are automatically added to the classpath of the project under the Web App Libraries category. WTP manages the build path of the project automatically based on the contents of the WEB-INF folder. Maven does not know about your WTP project classpath. It uses dependencies to manage external libraries and code that your project needs. Dependencies are defined in the POM and used to automatically construct a classpath for the Java compiler. Selected libraries are also included in the WEB-INF/lib folder. Maven encourages the use of repositories to store and share external libraries, and does not keep them with the project. Instead, Maven retrieves them from a repository when needed. Repositories provide a very consistent and manageable method for maintaining libraries. There is a default Internet-based central Maven repository that keeps most popular Java libraries, served from ibiblio.org at
http://www.ibiblio.org/maven/

On the other hand,WTP requires that these libraries be kept inside the WEB-INF/lib folder. There is code duplication here. In Maven 1.0, dependencies and WTP can coexist in a number of ways. One such method is to use a mechanism to override dependencies per project. This allows you to maintain your external libraries inside the WEB-INF/lib folder and override the JAR dependencies. Maven will then retrieve these libraries from your project location instead of the repository. In Maven 2.0, dependencies are always retrieved from a repository.

Lets review what you accomplished so far. You have created a dynamic Web project using the project layout conventions suggested by Maven (see Figure 6.46).

Example Projects

185

Figure 6.46

Project ExplorerMaven Web Project

Mavenizing the Project

The next step is defining the Maven POM that will automate builds, unit tests, documentation, project reporting, and so on. The POM is defined by an XML file named pom.xml (see Example 6.6). This file tells Maven everything that it needs to know about your project. Maven has tools that can create skeleton POMs, but we will create the POM from scratch. The snippet shown in Example 6.6 is the start of a POM for your Web application.
Example 6.6 Content of POM
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <artifactId>leagueplanet</artifactId> <groupId>com.leagueplanet</groupId> <name>LeaguePlanet.com Web Project</name> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <build>[...]</build> <dependencies>[...]</dependencies> </project>

186

CHAPTER 6 Organizing Your Development Project

The project artifactId corresponds to the Web application module in your project. Dependencies will define external libraries needed by your Web application. You will use the Struts framework, so struts*.jar and commons*.jar libraries must be present in this list. The build section tells Maven how the Java sources and other resources are organized. Maven project definition allows you to define filters for including or excluding source files. The build section is quite simple to set up, as shown in Example 6.7.
Example 6.7 Maven Build Section
<?xml version="1.0" encoding="UTF-8"?> <project> [...] <build> <finalName>${artifactId}-${version}</finalName> </build> </project>

The build section can be used to customize your project. Since you used the default location, you do not have to modify anything here. The finalName element automatically constructs the name of the exported WAR from other information provided in the POM. The dependency section is probably the longest (see Example 6.8).
Example 6.8 Maven Dependencies Section
<?xml version="1.0" encoding="UTF-8"?> <project> [...] <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>struts</groupId> <artifactId>struts</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>struts</groupId> <artifactId>struts-el</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>commons-validator</groupId> <artifactId>commons-validator</artifactId>

Example Projects

187

<version>1.1.4</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.0.3</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>antlr</groupId> <artifactId>antlr</artifactId> <version>2.7.5</version> </dependency> <dependency> <groupId>commons-digester</groupId> <artifactId>commons-digester</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>oro</groupId> <artifactId>oro</artifactId> <version>2.0.8</version> </dependency> <dependency> <groupId>servletapi</groupId> <artifactId>servletapi</artifactId> <version>2.3</version> <scope>compile</scope> </dependency> </dependencies> </project>

Each entry corresponds to an external JAR that is needed by your project. The Struts framework requires a few of these dependencies to be set. Some of these JARs are needed to compile your code; others, such as JUnit, are for testing. The JARs have a scope tag that defines when they are used. For example, by default all Struts JARs will be included with the Web application module, but JUnit has the scope test, so it will not be included. Remember that Maven gets the libraries defined in the dependencies from a repository. However, for WTP to function properly, you need to keep a copy of these libraries inside the src/webapp/WEB_INF/lib folder instead of the repository. Unfortunately, there is no tool to synchronize the dependencies and libraries.

188

CHAPTER 6 Organizing Your Development Project

You have defined the minimal Maven POM to build your Web application. Maven is typically run from the command line. Maven commands are also called goals. Goals are high-level tasks that can include other subtasks. Mevenide is an Eclipse plug-in for Maven that allows you to run Maven goals from the Eclipse IDE. Here you will use the command line. You can build a deployable Web module and a project site by running the maven clean package site goals. The package goal depends on other goals such as compile and test, so Maven will run them automatically. During the build, Maven creates a folder named target to store the generated files. The name and location of the generated files can be modified by additional settings. When you run Maven, you will get an output like that shown in Example 6.9.
Example 6.9 Maven Console Output
C:\workspace\LeaguePlanetWebProject>mvn clean package site [INFO] Scanning for projects... [INFO] [INFO] Building LeaguePlanet.com Web Project [INFO] task-segment: [clean, package] [INFO] [INFO] [clean:clean] [INFO] Deleting directory C:\workspace\LeaguePlanetWebProject\target [INFO] Deleting directory C:\workspace\LeaguePlanetWebProject\target\classes [INFO] Deleting directory C:\workspace\LeaguePlanetWebProject\target\test-classes [INFO] [resources:resources] [INFO] Using default encoding to copy filtered resources. [WARNING] While downloading servletapi:servletapi:2.3 This artifact has been relocated to javax.servlet:servlet-api:2.3. [INFO] [compiler:compile] Compiling 1 source file to C:\workspace\LeaguePlanetWebProject\target\classes [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] Compiling 1 source file to C:\workspace\LeaguePlanetWebProject\target\test-classes [INFO] [surefire:test] [INFO] Setting reports dir: C:\workspace\LeaguePlanetWebProject\target/surefire-reports T E S T S [surefire] Running com.leagueplanet.tests.LeaguePlanetBVTTest [surefire] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.01 sec [INFO] [site:site] [INFO] Generate "Continuous Integration" report. [ERROR] VM #displayTree: error : too few arguments to macro. Wanted 2 got 0 [ERROR] VM #menuItem: error : too few arguments to macro. Wanted 1 got 0 [INFO] Generate "Dependencies" report.

Example Projects

189

[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO] [INFO]

Generate "Issue Tracking" report. Generate "Project License" report. Generate "Mailing Lists" report. Generate "Source Repository" report. Generate "Project Team" report. Generate "Maven Surefire Report" report. Generate an index file for the English version. BUILD SUCCESSFUL Total time: 11 seconds Finished at: Sat May 13 15:48:09 EEST 2006 Final Memory: 9M/17M

That is all there is to building a WAR with Maven. You will see from the log that package is a composite goal. In addition to assembling a Web application module using the war goal, it runs the java goal to compile the classes and the test goal to compile and run the tests. Once the build is complete, you can browse the results of the build in the target folder (see Figure 6.47).

Figure 6.47

Project Site

190

CHAPTER 6 Organizing Your Development Project

So far, you could have done most of this using WTP, without the hassle of setting up Maven in the project. Building Web application modules is something WTP does well, and it does it automatically with minimal effort. But you can get more out of Maven. The next section shows you how to automate testing and reporting on the League Planet project using Maven.
Getting More Out of Maven

Now that you can build the Web application module using Maven, you can add tests and more project information to the POM to find out what more Maven can do.
Unit Tests with Maven

To run unit tests with Maven, you will create JUnit test cases and define required libraries, including JUnit in the project dependencies. Since you defined the JUnit dependencies in the previous section, you can start writing a test in the src/tests/ java source folder. In the Project Explorer, select LeaguePlanetWebProject, right click, and invoke the File New Source Folder. The New Source Folder wizard will open (see Figure 6.48).

Figure 6.48

Source Folder for Tests

Enter src/test/java as the folder name. Click Finish. A new source folder will be added to the project. To create a new JUnit test case, invoke the JUnit test case wizard using File New JUnit Test Case, and then enter package and class names, for example,

Example Projects

191

com.leagueplanet.tests

and LeaguePlanetBVTTests. Click Finish. The wizard will prompt you to add junit.jar to the project build path if it is not included there already. Accept it to add the JAR. JUnit JAR Is Defined Twice Remember that Maven does not know about your project classpath. Therefore it will not know about the JUnit JAR unless it is added to the POM dependencies. You add JUnit to the dependencies as shown in Example 6.10.
Example 6.10 Maven JUnit Dependency
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency>

This is inconvenient, but it is something that you will have to live with if you want to use Maven.

A new test class will be created at the location shown in Example 6.11.
Example 6.11 Maven Test Directory
/LeaguePlanetWebProject +- src/ | +- test/ | | +- java/ | | | +- com | | | | +- leagueplanet | | | | | +- tests | | | | | | +- LeaguePlanetBVTTests.java | | | | | | +- [...] other unit tests | [...]

Execute the Maven package site goals to run the tests. If you want to run the tests only, you just execute the test goal. Running the Maven test goal creates output as shown in Example 6.12.
Example 6.12 Maven Test Output
[INFO] [INFO] [INFO] [INFO] [INFO] [INFO] Scanning for projects... Building LeaguePlanet.com Web Project task-segment: [test] [resources:resources]

192

CHAPTER 6 Organizing Your Development Project

[INFO] Using default encoding to copy filtered resources. [WARNING] While downloading servletapi:servletapi:2.3 This artifact has been relocated to javax.servlet:servlet-api:2.3. [INFO] [compiler:compile] [INFO] Nothing to compile - all classes are up to date [INFO] [resources:testResources] [INFO] Using default encoding to copy filtered resources. [INFO] [compiler:testCompile] [INFO] Nothing to compile - all classes are up to date [INFO] [surefire:test] [INFO] Setting reports dir: C:\workspace\LeaguePlanetWebProject\target/surefire-reports T E S T S [surefire] Running com.leagueplanet.tests.LeaguePlanetBVTTest [surefire] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.03 sec [INFO] [INFO] BUILD SUCCESSFUL [INFO] [INFO] Total time: 2 seconds [INFO] Finished at: Sat May 13 15:58:43 EEST 2006 [INFO] Final Memory: 3M/6M [INFO]

You will find the Maven JUnit test reports under the target/surefire-reports folder. Of course, XML reports can be transformed into a more human-readable format, but you will see in the next section that Maven also does this for you (see Figure 6.49).
Project Information and Reports

The Maven project model can also contain information about the developers, configuration and version control systems, issue tracking, mailing lists, and other process-related project information. This information is used by Maven plug-ins to generate project information and reports. The listing shown in Example 6.13 provides the complete code for a typical Maven project model.

Example Projects

193

Figure 6.49

Maven JUnit Test Reports

Example 6.13 Listing of pom.xml


<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>leagueplanet</artifactId> <groupId>com.leagueplanet</groupId> <name>LeaguePlanet.com Web Project</name> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <organization> <name>LeaguePlanet.com</name> <url>http://www.leagueplanet.com/</url> </organization>

194

CHAPTER 6 Organizing Your Development Project

<description> An example project showing how to use eclipse WebTools Platform and Maven for Java Web Development. </description> <licenses> <license> <comments>Eclipse Public Licence (EPL)v1.0</comments> <url>http://www.eclipse.org/legal/epl-v10.html</url> </license> </licenses> <developers> <developer> <id>ndai</id> <name>Naci Dai</name> <email>naci.dai@eteration.com</email> <organization>Eteration</organization> </developer> <developer> <id>lmandel</id> <name>Lawrence Mandel</name> <email>lmandel@ca.ibm.com</email> <organization>IBM</organization> </developer> <developer> <id>ryman</id> <name>Arthur Ryman</name> <email>ryman@ca.ibm.com</email> <organization>IBM</organization> </developer> </developers> <build> <finalName>${artifactId}-${version}</finalName> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>struts</groupId> <artifactId>struts</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>struts</groupId> <artifactId>struts-el</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>commons-validator</groupId>

Example Projects

195

<artifactId>commons-validator</artifactId> <version>1.1.4</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.0.3</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>antlr</groupId> <artifactId>antlr</artifactId> <version>2.7.5</version> </dependency> <dependency> <groupId>commons-digester</groupId> <artifactId>commons-digester</artifactId> <version>1.7</version> </dependency> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>oro</groupId> <artifactId>oro</artifactId> <version>2.0.8</version> </dependency> <dependency> <groupId>servletapi</groupId> <artifactId>servletapi</artifactId> <version>2.3</version> </dependency> </dependencies> <reporting> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId> maven-project-info-reports-plugin </artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-report-plugin</artifactId> </plugin> </plugins> </reporting> </project>

196

CHAPTER 6 Organizing Your Development Project

The project reports are generated using the Maven site goal. This goal builds a local copy of the project site for reports, documentation, and reference. The result is generated into the target/site directory in the projects base directory, which contains an entire Web site of documentation (see Figure 6.50).

Figure 6.50

Maven Project Reports

Summary
We have described how modules and projects are managed in WTP. You now should have enough knowledge to start exploring these project styles and customizing them as you see fit. Web projects are very flexible, but they cant model every style of project that you can imagine or that is in use somewhere. Our advice to you is to use one of the more popular templates, such as the default ones created by WTP, or widely published conventions such as Maven. You can build on top of existing know-how

Summary

197

and make use of the experience that is readily available. When you are organizing your development, the last thing you want to be is surprised, so do take advantage of well-established best practices. You can now proceed to either Chapter 7, which covers the presentation layer, or Chapter 8, which covers business logic, depending on the type of development you want to start.

PREMIERE GOOgLE WEB TOOLKIt CONFERENcE

Meet the Voices That Matter


Google Web Toolkit enables developers to use their favorite Java tools to build Ajax applications without having to tackle the steep learning curve and quirks of JavaScript and CSS. At the Voices That Matter: Google Web Toolkit Conference, youll learn to leverage the power and functionality of GWT to write dynamic, standards-compliant, feature-rich Ajax applications. The speakers live and breathe Google Web Toolkit in their daily worksome because theyre members of the GWT team at Google, some because theyre deep in the GWT development trenches and have lots of experience to share. At the conference youll benet from their collective expertise, as they explore key GWT topics: David Geary, renowned Java author and consultant, on leveraging VOODOO in the browser for fun and prot. Billy Hoffman, American hacker, will manipulate, clobber and attack in our SECURITY session. Bruce Johnson, co-creator of GWT, delves into the GWT LIBRARIES, pointing out their breadth and explaining some subtle design decisions and the resulting benets. Kelly Norton, Google engineer and MIT Media Lab alumna, tackles USABILITY considerations, including UI design, history behavior, keyboard support, and accessibility. Joel Webber, co-creator of GWT, demonstrates best practices for web application PERFORMANCE and explains how to implement these practices using GWT. But the value of attending the conference goes far beyond the world class speakers. Mix and mingle with developers just like you and learn from their GWT experiences, building your developer network. Tools to facilitate this dialogue include a conference blog, code hacks, roundtables, and Birds of a Feather sessions.

JOIn ThE COnVERSATIOn. REgISTER TOdAY.

SPEAKERS
Scott Blum Andre Charland Ray Cromwell Rajeev Dayal Ryan Dewsbury David Geary Billy Hoffman

Adam Houghton

Rob Jellinghaus

Bruce Johnson

Dave Johnson

Shianjian Li

Dan Morrill

Kelly Norton

Dan Peterson

Toby Reyelts

John Tamplin

Joel Webber

Alexei White

GOOgLE WEB TOOLKIt cONFERENcE SchEduLE


MOndAY, dECEmbER 3, 2007PRE COnFEREnCE WORkShOpS 9:00-12:30 1:30-5:00 JavaScript Bootcamp Dave Johnson and Alexei White Ajax: The Big Picture Andre Charland and Alexei White A Business Case for Ajax with Google Web Toolkit Bruce Johnson

TUESdAY, dECEmbER 4, 2007 9:00-9:45 10:00-10:15 10:15-11:00 11:15-12:15 12:15-1:30 1:30-2:30 2:45-3:45 4:00-5:00 5:15-6:15 6:15-8:15 8:45-9:45 10:00-10:45 11:00-11:45 12:00-2:00 2:00-2:45 3:00-3:45 4:00-4:45 5:00-5:45 6:00-8:00 9:00-9:45 10:00-10:45 11:00-11:45 12:00-12:30 Creating Widgets Joel Webber Tour of GWT Core Libraries Bruce Johnson Architecture Best Practices Joel Webber Tools Panel Moderator: Adam Houghton Product Showcase, Bookstore Open and Birds of a Feather Sessions ThURSdAY, DECEmbER 6, 2007 Breakfast with the Experts: Moderated Attendee Roundtables Best Practices for Building Libraries Kelly Norton and Joel Webber API Integrations: Maps and Gears Deferred Binding Ray Cromwell Lunch and Product Showcase Bookstore Open Internationalization Shianjian Li JavaScript Native Interface Scott Blum Unit Tests and Benchmarking Toby Reyelts Security Billy Hoffman Performance Joel Webber Usability Kelly Norton Conference Registration Welcome

Keynote
Productivity Bruce Johnson and Dan Peterson Lunch GWT Apps in Production Client Server Communication Dan Morrill Voodoo in the Browser: Harnessing GWTs Power David Geary Applications Panel Moderator: Bret Taylor Product Showcase and Coding Roundtables wEdnESdAY, dECEmbER 5, 2007 Sponsor Breakfast and Presentation Remote Procedure Calls Rob Jellinghaus Understanding User Interfaces Rajeev Dayal

Deployment Best Practices Ryan Dewsbury and Bob Vawter Conference Wrap Up

For session abstracts, speaker biographies and schedule updates, please visit our Web site: www.VoicesThatMatter.com/GWT2007

Вам также может понравиться