Building a GAE+GWT application using the best practices, Part 5

This is the fifth installment of the series “Building a GAE+GWT application using the best practices“.

In the last post of the series, I’ve shown how to setup a client side GIN+MVP project. This post will discuss the actual building of the UI and GWT-RPC web service calls using GWT-Dispatch on the client side.

Use cases

Before we dive into the code, let’s go over again the use cases our little app has.

  • When the UI loads, it should automatically fetch the latest saved rate
  • Also, the table below the latest rate should display the 10 most recent rates stored in the data store
  • The “Refresh” button does the above two steps
  • The “Fetch latest” button fetches the rate from the bank website, store it in the data store, and insert the latest rate in the recent rate table

MVP pattern

For traditional desktop application, there’s the MVC (Model-View-Control) pattern that’s been in existence for over 20 years, since the Smalltalk days. However, the responsibility separation between the view and controller hasn’t been well defined and over the years, people have been arguing about what whether the business logic should be entirely in controller.

With the MVP (Model-View-Presenter) pattern, the view itself doesn’t contain any logic. The presenter manipulates the view according to business logic. Therefore, the pattern is also called “supervising controller” or “passive view”. This brings a huge benefit because now unit tests only have to deal with presenters, and mock out the view through the display interface. With this setup, the presenter unit tests can be run entirely in JVM. Otherwise, the tests need to involve GWT widgets, which can only be tested with GWTTestCase, which takes a lot longer to run.

MainView

Here I’m using the new GWT2 UiBinder feature. UiBinder makes developing UI less boring.

MainView.ui.xml

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
	xmlns:g="urn:import:com.google.gwt.user.client.ui">
	<ui:style>
		.rateDisplay {
			font-size: x-large;
			font-weight: bolder;
		}
		
		.mainPanel {
			padding: 10px;
		}
	</ui:style>

	<ui:with type="ratechecker.client.bundles.RateCheckerClientBundle"
		field="bundle"></ui:with>
	<g:DecoratorPanel height="200px">
		<g:VerticalPanel styleName="{style.mainPanel}" verticalAlignment="ALIGN_TOP">
			<g:Label>Latest Selling Rate</g:Label>
			<g:Image resource="{bundle.loading}" visible="false"
				ui:field="loading"></g:Image>
			<g:Label ui:field="rateDisplay" styleName="{style.rateDisplay}"></g:Label>
			<g:HorizontalPanel>
				<g:Button ui:field="fetchLatest">Fetch Latest</g:Button>
				<g:Button ui:field="refresh">Refresh</g:Button>
			</g:HorizontalPanel>

			<g:Label>Recent rates</g:Label>
			<g:FlexTable ui:field="rateTable">
			</g:FlexTable>
		</g:VerticalPanel>
	</g:DecoratorPanel>
</ui:UiBinder> 

UiBinder can inter-operate with GWT2 ClientBundle. If you have used GWT1.x’s ImageBundle, ClientBundle is similar to that, except now with ClientBundle, other client resources are able to be bundled such as CSS stylesheet and external text resource.

MainPresenter.Display

The display interface is the only thing presenter knows about the UI, and the presenter operates/manipulates UI only through the display interface.

The display interface can be standalone, but I find it’s much more convenient to have it as an inner interface inside the presenter class.

	public interface Display extends WidgetDisplay {
		HasText getRateDisplayLabel();
		HasClickHandlers getFetchLatest();
		HasClickHandlers getRefresh();

		void setEnabledFetchLatestButton(boolean isEnabled);
		void setShowLoadingCurrentRate(boolean isLoading);
		/**
		 * Add the rate to the recent rate table.
		 * @param rate
		 * 		The {@link Rate} object
		 * @param toHead
		 * 		<code>true</code> - rate is inserted to the beginning of the table
		 * 		<code>false</code> - rate is appended to the end of the table
		 */
		void addToRecentRates(Rate rate, boolean toHead);
		/**
		 * Clear the recent rates table.
		 */
		void clearRecentRates();
	}

Here we use the “characteristic interface” of the UI elements as return type as they can be mocked. For things that cannot be returned as characteristic interfaces (like FlexTable), we provide methods for the presenter to manipulate the state of the UI objects (such as clearRecentRates()).

MainView.java

Now we have the display interface, we can map these interface methods onto our UI.

package ratechecker.client.mvp;

public class MainView extends Composite implements MainPresenter.Display {

	private static MainViewUiBinder uiBinder = GWT
	.create(MainViewUiBinder.class);

	interface MainViewUiBinder extends UiBinder<Widget, MainView> {
	}

	@UiField
	Button refresh;

	@UiField
	Button fetchLatest;

	@UiField
	Label rateDisplay;

	@UiField
	FlexTable rateTable;

	@UiField
	Image loading;

	private final DateTimeFormat _dateTimeFormat;

	@Inject
	public MainView(final DateTimeFormat dateTimeFormat) {
		_dateTimeFormat = dateTimeFormat;
		initWidget(uiBinder.createAndBindUi(this));
	}

	@Override
	public HasClickHandlers getFetchLatest() {
		return fetchLatest;
	}

	@Override
	public Widget asWidget() {
		return this;
	}

	@Override
	public HasText getRateDisplayLabel() {
		return rateDisplay;
	}

	@Override
	public void setEnabledFetchLatestButton(final boolean isEnabled) {
		fetchLatest.setEnabled(isEnabled);
	}

	@Override
	public void addToRecentRates(final Rate rate, final boolean toHead) {
		final int newRowIdx = toHead ? 0 : rateTable.getRowCount();
		rateTable.insertRow(newRowIdx);
		rateTable.setText(newRowIdx, 0, _dateTimeFormat.format(rate.getTimeFetched()));
		rateTable.setText(newRowIdx, 1, String.valueOf(rate.getRate()));
	}

	@Override
	public void clearRecentRates() {
		rateTable.removeAllRows();
	}

	@Override
	public HasClickHandlers getRefresh() {
		return refresh;
	}

	@Override
	public void setShowLoadingCurrentRate(final boolean isLoading) {
		loading.setVisible(isLoading);
		rateDisplay.setVisible(!isLoading);
	}

	@Override public void startProcessing() { }

	@Override public void stopProcessing() { }
}

A lot of this is boilerplate code to satisfy both UiBinder and GWT-presenter.Display interface. Ideally, the VIew shouldn’t do too much, if any at all. Realistically, this is harder to achieve.

MainPresenter

Finally, we can show you the presenter code.


public class MainPresenter extends WidgetPresenter<MainPresenter.Display> {

	private final DispatchAsync _dispatch;

	private final ILog _logger;

	@Inject
	public MainPresenter(final Display display, final EventBus eventBus, final DispatchAsync dispatch, final ILog logger) {
		super(display, eventBus);
		_dispatch = dispatch;
		_logger = logger;
	}

	@Override
	protected void onBind() {
		registerHandler(display.getFetchLatest().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(final ClickEvent event) {
				fetchSellingRate();
			}

		}));

		registerHandler(eventBus.addHandler(RateFetchedEvent.TYPE, new RateFetchedHandler() {

			@Override
			public void onRateFetched(final Rate rate) {
				saveRate(rate);
			}

		}));

		registerHandler(eventBus.addHandler(RateSavedEvent.TYPE, new RateSavedHandler() {

			@Override
			public void onRateSaved(final Rate rate) {
				display.addToRecentRates(rate, true);
			}

		}));

		registerHandler(display.getRefresh().addClickHandler(new ClickHandler() {

			@Override
			public void onClick(final ClickEvent event) {
				getLatestSavedRates();
			}

		}));

		getLatestSavedRates();
	}

	void getLatestSavedRates() {
		display.setShowLoadingCurrentRate(true);

		final GetRates getRates = new GetRates();

		_dispatch.execute(getRates, new AsyncCallback<GetRatesResult>() {

			@Override
			public void onFailure(final Throwable caught) {
				display.setShowLoadingCurrentRate(false);
				_logger.error("Unable to get saved rates: " + caught.getMessage());
			}

			@Override
			public void onSuccess(final GetRatesResult result) {
				display.setShowLoadingCurrentRate(false);
				display.clearRecentRates();

				for (final Rate rate : result.getRates()) {
					display.addToRecentRates(rate, true);
				}

				// Put the latest rate in the box
				if (result.getRates().size() > 0) {
					final Rate latestRate = result.getRates().get(0);
					display.getRateDisplayLabel().setText(String.valueOf(latestRate.getRate()));
				}
			}
		});

	}

	void fetchSellingRate() {
		display.setShowLoadingCurrentRate(true);
		final CheckRate checkRate = new CheckRate(RateType.Selling);
		_dispatch.execute(checkRate, new AsyncCallback<CheckRateResult>() {

			@Override
			public void onFailure(final Throwable caught) {
				display.setShowLoadingCurrentRate(false);
				_logger.error("Unable to fetch rate: " + caught.getMessage());
			}

			@Override
			public void onSuccess(final CheckRateResult result) {
				display.setShowLoadingCurrentRate(false);
				// enable the fetch button
				display.setEnabledFetchLatestButton(true);
				display.getRateDisplayLabel().setText(String.valueOf(result.getRate().getRate()));
				eventBus.fireEvent(new RateFetchedEvent(result.getRate()));
			}

		});

		// disable the fetch button until RPC succeeds
		display.setEnabledFetchLatestButton(false);
	}

	void saveRate(final Rate rate) {
		final SaveRate saveRate = new SaveRate(rate);

		_dispatch.execute(saveRate, new AsyncCallback<SaveRateResult>() {

			@Override
			public void onFailure(final Throwable caught) {
				_logger.error("Unable to save rate: " + caught.getMessage());
			}

			@Override
			public void onSuccess(final SaveRateResult result) {
				eventBus.fireEvent(new RateSavedEvent(rate));
			}

		});

	}

	@Override protected void onPlaceRequest(final PlaceRequest request) { }

	@Override protected void onUnbind() {}

	@Override public void refreshDisplay() {}

	@Override public void revealDisplay() {}

	@Override public Place getPlace() { return null; }
}

In the binding process, the event handlers are attached to the view components. MainPresenter.bind() was explicitly called by AppPresenter.go(). This is a simple application with one presenter. If there are more presenters, AppPresenter needs to manage the state of these sub-presenters: if they’re active, the bind() method is called. If the presenter is no-longer active, the presenter’s unbind() method should be called to un-attach the handlers, so they don’t interfere with the event handlers that are currently in the active presenter.

The presenter is also responsible for making web service calls and deal with the returns. To call GWT-RPC web service using GWT-dispatch, we inject a DispatchAsync, which is an asynchronous counter part of the DispatchServlet introduced a few posts ago.

To call a web service, we simply construct an action object with required parameters and pass it in DispatchAsync.execute() and expect an AsyncCallback of type result that’s coupled with the action. (remember each action has a coupled result type). Also, in this application, every action has a related event to indicate whether the action is successful. The event is thrown onto the event bus, so any interested party can handle that. The main benefit of using event bus is that my web service calls don’t have to be coupled with the subsequent actions. For example, saveRate() method is responsible for making the web service calls, but the subsequent action (adding the saved rate to the recent rate table) isn’t part of saveRate() method, and it shouldn’t be. If in the future, some other actions need to be carried out when a rate is saved, we just have to add the action in the RateSavedHandler, and indeed, if another part of the UI (not visible by main presenter) need to do something after the rate is saved, that presenter only needs to handle that event in there without affecting saveRate() method at all.

For view the full source code, take a look at the project I created on GitHub.

EDIT:For any Google App Engine experts out there happened to be reading this post, I’m having trouble with the performance of this simple app. Seems like the data store is taking way too much time executing my query. Initially I thought it was because URL fetch is slow, but I recently added a property in Rate entity to track the time spent on fetching the URL and every request takes less than 1 second. However, the GetRates action takes a long time to return (usually ~3 to 5 seconds, sometimes even over 10 seconds). It’s a simple query ordering on a single property so no complex index is needed. So I’m wondering what’s wrong here.

Building a GAE+GWT application using the best practices, Part 4

This is the fourth installment of the series “Building a GAE+GWT application using the best practices“.

In the last blog post, we went over how to write GWT-RPC handlers using GWT-dispatch and dependency injection (Guice). This section, we’re going to see how the client side is set up.

Dependencies

We need the following dependencies

They need to be on the classpath when you compile your GWT code, but not under the war directory like the server dependencies need to be.

Module definition

The first step is to declare the inherited GWT modules in the module XML file:
RateChecker.gwt.xml

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to="ratechecker">
    <inherits name="com.google.gwt.user.User" />
    <inherits name="com.google.gwt.inject.Inject" />
    <inherits name="net.customware.gwt.dispatch.Dispatch" />
    <inherits name="net.customware.gwt.presenter.Presenter" />
    <inherits name="com.allen_sauer.gwt.log.gwt-log-DEBUG" />
    <inherits name="com.google.gwt.user.theme.chrome.Chrome"/>

    <entry-point class="ratechecker.client.RateChecker" />

    <source path="client" />
    <source path="shared" />

</module>

Here we specify the explicitly the packages need to be included for compiling – “client” and “shared”. If not specified, GWT will by default compile every source file under the client package.

Create a Gin Module

Gin and Guice implements the same API (or rather, Gin has the same interface as Guice), but Gin uses GWT deferred binding “magic”. Similar to what we have on the server side, on the client side, we start by defining our module:
RateCheckerClientModule:

public class RateCheckerClientModule extends AbstractPresenterModule {

	public RateCheckerClientModule() {
	}

	@Override
	protected void configure() {

		bind(EventBus.class).to(DefaultEventBus.class).in(Singleton.class);
		bind(PlaceManager.class).in(Singleton.class);

	}
}

To start up, we bind EventBus and PlaceManager in the singleton scope. They’re both provided by GWT-mvp library.

AppPresenter

There are different ways to facilitate the MVP pattern but the way I find the most convenient is to have an AppPresenter manage all subsequent presenters. The view the AppPresenter represents is the RootPanel of GWT.

public class AppPresenter {

	private HasWidgets _container;

	private final MainPresenter _mainPresenter;


	@Inject
	public AppPresenter(final MainPresenter mainPresenter) {
		_mainPresenter = mainPresenter;
		_mainPresenter.bind();
	}


	public void go(final HasWidgets container) {
		_container = container;
		_container.clear();
		_container.add(_mainPresenter.getDisplay().asWidget());
	}
}

Here, MainPresenter is the actual UI. The go() method of AppPresenter is for the module entry point to call when the module first initializes. We need to add the bindings to the client module:

        ...
	@Override
	protected void configure() {

		bind(EventBus.class).to(DefaultEventBus.class).in(Singleton.class);
		bind(PlaceManager.class).in(Singleton.class);
		bind(ILog.class).to(GwtLogAdapter.class).in(Singleton.class);
		bind(AppPresenter.class);

		bindPresenter(MainPresenter.class, MainPresenter.Display.class, MainView.class);
	}
        ...

Dependencies

We need the following dependencies

They need to be on the classpath when you compile your GWT code, but not under the war directory like the server dependencies need to be.

Module definition

The first step is to declare the inherited GWT modules in the module XML file:
RateChecker.gwt.xml

<?xml version="1.0" encoding="UTF-8"?>
<module rename-to="ratechecker">
    <inherits name="com.google.gwt.user.User" />
    <inherits name="com.google.gwt.inject.Inject" />
    <inherits name="net.customware.gwt.dispatch.Dispatch" />
    <inherits name="net.customware.gwt.presenter.Presenter" />
    <inherits name="com.allen_sauer.gwt.log.gwt-log-DEBUG" />
    <inherits name="com.google.gwt.user.theme.chrome.Chrome"/>

    <entry-point class="ratechecker.client.RateChecker" />

    <source path="client" />
    <source path="shared" />

</module>

Here we specify the explicitly the packages need to be included for compiling – “client” and “shared”. If not specified, GWT will by default compile every source file under the client package.

Create a Gin Module

Gin and Guice implements the same API (or rather, Gin has the same interface as Guice), but Gin uses GWT deferred binding “magic”. Similar to what we have on the server side, on the client side, we start by defining our module:
RateCheckerClientModule:

public class RateCheckerClientModule extends AbstractPresenterModule {

	public RateCheckerClientModule() {
	}

	@Override
	protected void configure() {

		bind(EventBus.class).to(DefaultEventBus.class).in(Singleton.class);
		bind(PlaceManager.class).in(Singleton.class);

		bind(AppPresenter.class);
		bindPresenter(MainPresenter.class, MainPresenter.Display.class, MainView.class);
	}

We’ll defer the introduction of MainPresenter, MainView and other UI related components to the next post.

Ginjector

Similar to “Injector” interface on the server side, the client side needs to define a Ginjector that act as a gateway for Gin managed object instances.

RateCheckerGinjector.java


@GinModules({RateCheckerClientModule.class, ClientDispatchModule.class})
public interface RateCheckerGinjector extends Ginjector {

	AppPresenter getAppPresenter();

}

Here the annotation @GinModules({…}) makes the instances managed by RateCheckerClientModule and ClientDispatchModule available for the ginjector. ClientDispatchModule binds DispatchAsync interface, which is what we will use to interface with the web service methods.

Entry Point

Finally, here’s the module entry point:

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class RateChecker implements EntryPoint {

	RateCheckerGinjector _injector = GWT.create(RateCheckerGinjector.class);

	@Override
	public void onModuleLoad() {

		final AppPresenter appPresenter = _injector.getAppPresenter();
		appPresenter.go(RootPanel.get("root"));
	}

}

GWT.create(…) statement here creates the ginjector at runtime. Behind the scene, it generates a class (by the name of something like RateCheckerGinjector_Impl) that contains the code to instantiate the bound classes, and when Gin sees a @Inject annotation on a class’s constructor, it provides the instances with the correct scope from the dependency injection container (Ginjector) to the constructor so that the said class can be instantiated.

The onModuleLoad() method doesn’t do much. It simple binds the appPresenter with the RootPanel where the app’s UI is going to be displayed.

I know a lot of the concrete UI creation has been left out of this post, but hopefully it will become clearer once the next post is in.

Building a GAE+GWT application using the best practices, Part 3

This is the third installment of the series “Building a GAE+GWT application using the best practices“.

In this part of the series, we’re going to explore the designing of the web services for RateChecker and coding them using the command pattern from GWT-dispatch based on Ray Ryan’s presentation.

The big picture


To correctly implement web services using the command pattern, we first have to get the big picture. There are three “actors” involved in this: an action, a result and a handler.

Action

An action is used to store the parameters of the web service call (if any). For instance, a CheckRate action needs to know what type of rate the user is checking: buying rate? selling rate? currency?

Result

A result object stores the result (duh…) of the web service call. In the case of CheckRate method, the result is the rate object containing the details of the rate.

Handler

A handler is the actual “worker” that actually does the work of checking the rate. In this case, the check rate method fetches the posted rate page , parses the text (if needed) to get the rate information.

Dispatch and DispatchAsync

A Handler is executed on the server side (by the DispatchServlet we saw in the last post). On the client side, there’s a counterpart “DispatchAsync”, which is the asynchronous interface that the client code calls.

Implementing web service methods

Now that we have the big picture in place, we’re going to look into how to actually implement them.
The first step is to define a domain model. In this case, it’s our Rate class:

@PersistenceCapable(identityType=IdentityType.APPLICATION)
public class Rate implements Serializable {

	private static final long serialVersionUID = -4415279469780082174L;

	@PrimaryKey
	@Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
	private Long id;

	@Persistent
	private RateType type;

	@Persistent
	private Date timeFetched;

	@Persistent
	private Double rate;

	public Rate() {
	}
        // ... getters and setters omitted
}
public enum RateType {
	Selling,
	Buying,
}

In our example application, we are going to define three simple web methods:

  • Check rate: use Url fetch to get the posted rate page and return a rate object from that.
  • Save rate: persist the rate object into the data store.
  • Get rate: get the rates from the data store.

Check rate

As we have shown in the big picture, every action needs three pieces: action, result (both in shared package, as they will be used by both the client and the server) and the handler (lives in the server package).

For CheckRate action, we need to specify the type of rate it needs to check. For simplicity, I’m always dealing with USD/CAD rate. The parameter here is only for whether to check for buying rate or selling rate.

public class CheckRate implements Action<CheckRateResult> {

	private static final long serialVersionUID = -1716760883016361503L;

	private RateType _type;

	public CheckRate() {
	}

	public CheckRate(final RateType type) {
		_type = type;
	}

	public void setType(final RateType type) {
		_type = type;
	}

	public RateType getType() {
		return _type;
	}

}

The result is designed to hold the returned Rate object.

public class CheckRateResult implements Result {

	private static final long serialVersionUID = -9099789297842581458L;

	private Rate _rate;

	public CheckRateResult() {
	}

	public CheckRateResult(final Rate rate) {
		_rate = rate;
	}

	public void setRate(final Rate rate) {
		_rate = rate;
	}

	public Rate getRate() {
		return _rate;
	}
}

Word of caution: because both action and result are serialized and sent over the wire as part of GWT-RPC call, they are required to have a default public constructor.

Now, on to the handler:

public class CheckRateHandler implements ActionHandler<CheckRate, CheckRateResult> {

	public static final String URL_BUY = "http://www.ingdirect.ca/en/datafiles/rates/usbuying.html";

	public static final String URL_SELL = "http://www.ingdirect.ca/en/datafiles/rates/usselling.html";

	public CheckRateHandler() {
	}

	@Override
	public CheckRateResult execute(final CheckRate action, final ExecutionContext ctx) throws ActionException {
		final CheckRateResult retval = new CheckRateResult();

		String strUrl = null;
		switch (action.getType()) {
		case Buying:
			strUrl = URL_BUY;
			break;
		case Selling:
			strUrl = URL_SELL;
			break;
		}

		try {
			final URL url = new URL(strUrl);

			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(url.openStream()));

				final double dRate = Double.parseDouble(br.readLine());

				final Rate rate = new Rate();
				rate.setRate(dRate);
				rate.setType(action.getType());
				rate.setTimeFetched(new Date());

				retval.setRate(rate);

			} finally {
				if (br != null)
					br.close();
			}
		} catch (final MalformedURLException e) {
			e.printStackTrace();
			throw new ActionException(e);
		} catch (final IOException e) {
			e.printStackTrace();
			throw new ActionException(e);
		} catch (final NumberFormatException e) {
			e.printStackTrace();
			throw new ActionException(e);
		}

		return retval;
	}
        // ... other methods omitted
}

As you can see, the handler does the actual work of fetching the rate using URL Fetch service offered by Google App Engine.

The other two web method implementations are similar. You can follow the project on Github here. In the next section, I’m going to go over the building of the UI in GWT, as well as making AJAX calls from GWT to the server.

Building a GAE+GWT application using the best practices, Part 2

This is the second installment of the series “Building a GAE+GWT application using the best practices“.

In Part 2, we’re going to go over project setup for GAE and GWT applications, and wire the server (servlet) using Guice and GWT-Dispatch.

Project setup

I’m using Eclipse as my development environment. Install Google Eclipse plugin, and install the provided GWT (2.0.2) and GAE (1.3.1) with the plugin. Create a new project in Eclipse using the “New web application project” wizard, and create a sample project.

Now, because during deployment, GAE applications are executed within its own servlet container, all dependencies have to be placed inside the directory /war/WEB-INF/lib. Go ahead, download Guice, GWT-dispatch, GWT-log, commons-logging and log4j. Put the jar files inside /war/WEB-INF/lib directory. Then in Eclipse, select the jars you just placed, right click and select “Add to build path”. Your lib directory should look something like this:

“Wiring” the server

Now that the project is setup, we need to wire the server to utilize the dependency injection container Guice. The details can be found here but in short, we need to do the following:

Modify web.xml

Find web.xml in /war/WEB-INF. In traditional GWT-RPC development, every service needs to be written as a servlet and declared in web.xml. For Guice + GWT-dispatch, we only need a filter and a listener (as the entry point).

<webapp>
        [...]
	<filter>
		<filter-name>guiceFilter</filter-name>
		<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>guiceFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<listener>
		<listener-class>ratechecker.server.guice.GuiceServletConfig</listener-class>
	</listener>
        [...]
</webapp>

Here, our listener is ratechecker.server.guice.GuiceServletConfig. It reads like the following

public class GuiceServletConfig extends GuiceServletContextListener {

	private ServletContext _ctx;

	@Override
	public void contextDestroyed(final ServletContextEvent servletContextEvent) {
		_ctx = null;
		super.contextDestroyed(servletContextEvent);
	}

	@Override
	public void contextInitialized(final ServletContextEvent servletContextEvent) {
		_ctx = servletContextEvent.getServletContext();
		super.contextInitialized(servletContextEvent);
	}

	@Override
	protected Injector getInjector() {
		return Guice.createInjector(new GuiceServerModule(), new DispatchServletModule());
	}

}

This code is borrowed from Hupa. The responsibility of this servlet context listener is to construct an injector (achieved by the last method). Here, our injector contains two modules, ratechecker.server.guice.GuiceServerModule and ratechecker.server.guice.DispatchServletModule.

DispatchServletModule

public class DispatchServletModule extends ServletModule {
	@Override
	protected void configureServlets() {
		super.configureServlets();
		serve("/ratechecker/dispatch").with(RateCheckerDispatchServlet.class);
	}
}

This module has a mapping of URIs and its serving classes. It serves “/ratechecker/dispatch” with RateCheckerDispatchServlet, which is the entry point for GWT-dispatch.

GuiceServerModule

public class GuiceServerModule extends ActionHandlerModule {

	public GuiceServerModule() {
	}

	@Override
	protected void configureHandlers() {
            // declare bindings
	}

}

This is where you declare your bindings for the application. We’ll come back to this file frequently as the application develops.

RateCheckerDispatchServlet

@Singleton
public class RateCheckerDispatchServlet extends DispatchServiceServlet {

	private static final long serialVersionUID = 4895255235709260169L;

	private final Log _logger;

	@Inject
	public RateCheckerDispatchServlet(final Dispatch dispatch, final Log logger) {
		super(dispatch);
		_logger = logger;
	}

	@Override
	public Result execute(final Action<?> action) throws ActionException {
		try {
			_logger.info("executing: " + action.getClass().getName());
			final Result res = super.execute(action);
			_logger.info("finished: " + action.getClass().getName());
			return res;
		} catch (final ActionException ae) {
			_logger.error(ae.getMessage());
			ae.printStackTrace();
			throw ae;
		} catch (final Exception e) {
			_logger.error("Unexpected exception: " + e.getMessage());
			e.printStackTrace();
		}
		return null;
	}
}

This servlet extends from GWT-dispatch’s DispatchServiceServlet. It’s main responsibility is to provide unified logging.

Notice you cannot run the application, because Guice is complaining that there’s no binding for org.apache.commons.logging.Log, which we declared as a dependency for RateCheckerDispatchServlet. We go ahead write our LogProvider (to provide lazy initialization for the Log object to its users)

LogProvider

public class LogProvider implements Provider<Log> {

	@Override
	public Log get() {
		return new Log4JLogger("RateCheckerLogger");
	}

}

Now the binding should be added to GuiceServerModule:

[...]
	@Override
	protected void configureHandlers() {
            bind(Log.class).toProvider(LogProvider.class).in(Singleton.class);
	}
[...]

Now everytime Guice sees Log.class declared as a dependency in the constructor, it uses LogProvider.get() method to retrieve an instance of the log if there’s none, and uses the existing log instance if it’s been initialized (because of the singleton scope).

In the end, your server package should look like this:

We haven’t covered PersistenceManagerProvider but it’s the same idea as LogProvider. It provides an instance of PersistenceManager, which is used by the data store related action handlers to deal with data persistence.

That’s it for server wiring. In the next blog post, I’ll go through designing and writing GWT-RPC services using Guice and GWT-dispatch.

Building a GAE+GWT application using the best practices, Part 1

This is the first installment of the series “Building a GAE+GWT application using the best practices“.

Introduction

In the next few blog posts, I’m going to present my experience building a simple (but non-trivial) web application using GWT and Google App Engine, while applying the best practices introduced by Ray Ryan in his excellent presentation at Google IO last year.

The application I’m going to build is called RateChecker. It’s simply a tool that goes fetches the posted USD/CAD exchange rate from a bank website, persists the rate to the data store, and present the user with the recent rates when requested. It can potentially do more (like generating a histogram of the rates, etc), but for the purpose of blog series, I’m going with the basics to illustrate the implementation pattern without losing my bearings in the embellishing.

Here’s a screenshot of the finished application:

The Goals

I intend to use this minimal application to practice using the following technologies/techniques:

  • Server/Persistence tier:
    • Google Guice as dependency injection container on the server side
    • JDO as the persistence layer
    • AppEngine Cron task
    • Command pattern for request handling
  • Client tier:
    • Google GIN as dependency injection container on the client side
    • Model-View-Presenter pattern on the client side
    • EventBus to decouple components
    • Command pattern for remote service calls
  • Unit Testing on both Client/Server side with mock objects

Also I plan to rewrite the service layer with one of the alternate JVM language, such as Scala or Clojure, if I my schedule allows and I have enough motivation.

Follow

Get every new post delivered to your Inbox.