TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Colorado. Besides tech, I enjoy landscape photography and share my work at ColoradoPhoto.gallery.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 241 other followers

  • Sleepless Nights…

    December 2017
    S M T W T F S
    « May    
     12
    3456789
    10111213141516
    17181920212223
    24252627282930
    31  
  • Blog Stats

    • 883,697 hits

Archive for the ‘Model-View-Presenter’ Category

SelectOneListBox for use with GWT+MVP

Posted by David Chandler on April 1, 2010

According to the Model-View-Presenter approach to GWT development, presenters should not know about specific Widgets in views, but rather call methods on interfaces like HasValue and HasClickHandlers. In practice, this works well with relatively simple widgets like TextBox whose behavior can be described to the presenter in terms of a single interface such as HasValue. However, GWT doesn’t yet provide suitable interfaces for all Widgets. One such example is the ListBox, which implements only HasChangeHandlers and HasName. Wouldn’t it be nice if there were a HasValue equivalent for ListBox that would let you get and set the selected value as well as populate the list?

Here’s my idea for such an interface:

package com.turbomanage.gwt.client.ui.widget;

import java.util.Collection;

import com.google.gwt.user.client.ui.HasValue;

/**
 * MVP-friendly interface for use with any widget that can be populated
 * with a Collection of items, one of which may be selected 
 * 
 * @author David Chandler
 *
 * @param <T>
 */
public interface HasSelectedValue<T> extends HasValue<T>
{
	void setSelections(Collection<T> selections);

	void setSelectedValue(T selected);
	
	T getSelectedValue();
}

In retrospect, the method name setSelections may be a bit confusing. It refers to all available options (perhaps setOptions instead?), not the one selected value.

And here’s a SelectOneListBox widget that implements the interface (astute readers may note a nod to JSF in the name…). It extends GWT’s ListBox, which simplifies implementation of the methods related to HasValue.

package com.turbomanage.gwt.client.ui.widget;

import java.util.ArrayList;
import java.util.Collection;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.ListBox;

/**
 * A ListBox that can be populated with any Collection
 * 
 * Published under Apache License v2
 * 
 * @author David Chandler
 * @param <T>
 */
public class SelectOneListBox<T> extends ListBox implements HasSelectedValue<T>
{

	public interface OptionFormatter<T>
	{
		abstract String getLabel(T option);
		abstract String getValue(T option);
	}
	
	private boolean valueChangeHandlerInitialized;
	private T[] options;
	private OptionFormatter<T> formatter;

	public SelectOneListBox(Collection<T> selections, OptionFormatter<T> formatter)
	{
		setSelections(selections);
		setFormatter(formatter);
	}

	public SelectOneListBox(OptionFormatter<T> formatter)
	{
		this(new ArrayList<T>(), formatter);
	}

	public void setFormatter(OptionFormatter<T> formatter)
	{
		this.formatter = formatter; 
	}

	@SuppressWarnings("unchecked")
	@Override
	public void setSelections(Collection<T> selections)
	{
		// Remove prior options
		if (options != null)
		{
			int numItems = this.getItemCount();
			int firstOption = numItems - options.length;
			for (int i=firstOption; i<numItems; i++)
				this.removeItem(firstOption);
		}
		options = (T[]) selections.toArray();
		for (T option : options)
		{
			String optionLabel = formatter.getLabel(option);
			String optionValue = formatter.getValue(option);
			this.addItem(optionLabel, optionValue);
		}
	}

	@Override
	public T getSelectedValue()
	{
		if (getSelectedIndex() >= 0)
		{
			String name = getValue(getSelectedIndex());

			for (T option : options)
			{
				if (formatter.getValue(option).equals(name))
					return option;
			}
		}

		return null;
	}

	@Override
	public void setSelectedValue(T value)
	{
		if (value == null)
			return;
		
		for (int i=0; i < this.getItemCount(); i++)
		{
			String thisLabel = this.getItemText(i);
			if (formatter.getLabel(value).equals(thisLabel))
			{
				this.setSelectedIndex(i);
				return;
			}
		}
		throw new IllegalArgumentException("No index found for value " + value.toString());
	}

	/*
	 * Methods to implement HasValue 
	 */
	
	@Override
	public T getValue()
	{
		return this.getSelectedValue();
	}

	@Override
	public void setValue(T value)
	{
		this.setValue(value, false);
	}

	@Override
	public void setValue(T value, boolean fireEvents)
	{
		T oldValue = getValue();
		this.setSelectedValue(value);
		if (fireEvents)
		{
			ValueChangeEvent.fireIfNotEqual(this, oldValue, value);
		}
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<T> handler)
	{
		// Initialization code
		if (!valueChangeHandlerInitialized)
		{
			valueChangeHandlerInitialized = true;
			super.addChangeHandler(new ChangeHandler()
			{
				public void onChange(ChangeEvent event)
				{
					ValueChangeEvent.fire(SelectOneListBox.this, getValue());
				}
			});
		}
		return addHandler(handler, ValueChangeEvent.getType());
	}

}

The SelectOneListBox constructor takes any collection and an OptionsFormatter which tells it how to get the label and value associated with each item in the collection. Here’s an example of its use:

		selectPrayerList = new SelectOneListBox<PrayerList>(new OptionFormatter<PrayerList>()
		{
			@Override
			public String getLabel(PrayerList option)
			{
				return option.getName();
			}

			@Override
			public String getValue(PrayerList option)
			{
				return option.getId().toString();
			}
		});

And finally, an example of populating the SelectOneListBox in a presenter:

HasSelectedValue<PrayerList> getPrayerListFilter();
...
display.getPrayerListFilter().setSelections(result.getPrayerLists());

Because HasSelectedValue extends GWT’s HasValue, you can also add ValueChangeHandlers in the presenter like this:

		display.getPrayerListsBox().addValueChangeHandler(new ValueChangeHandler<PrayerList>()
		{
			@Override
			public void onValueChange(ValueChangeEvent<PrayerList> event)
			{
				... event.getValue() ...
			}
		});

Now, the problem always comes up (and this is probably the reason that GWT’s ListBox doesn’t implement a HasValue-like interface already), how do you add to the list things which are not model items, that is, not in the Collection? A common example is a “Select one” or “New…” prompt to appear in the list box. This is not a problem if you’re using ListBox directly, as you can add any String with addItem(). But it is a problem for SelectOneListBox. Because it implements HasSelectedValue, all options must be of type T. So you can do one of four things:

  1. Hard-code your presenter to ListBox instead of an interface (very unsatisfying)
  2. Register ValueChangeHandlers in the view and let the view call a method on the presenter (bi-directional MVP)
  3. Punt and make a fake model item representing your prompt
  4. Don’t put such items in list boxes. It confuses screen readers, anyway.

I think #4 is actually the most correct answer and fight for it wherever I can. But when screen real estate is precious, I’m willing to break the rules a little. Since I’m using gwt-presenter, #2 is not an option, which leaves #3. It offends my sensibilities, but it’s quite easy and it works. Here’s an example:

				ArrayList<PrayerList> prayerLists = new ArrayList<PrayerList>();
				// -1 represents an ID that will never be used in a real PrayerList
				prayerLists.add(new PrayerList(-1, "Select one"));
				prayerLists.addAll(result.getLists());
				display.getPrayerListFilter().setSelections(prayerLists);

While we’re at it, we can even add a little bit of CSS to style our fake -1 object with a line underneath to act as a menu separator:

/* Select one */
option[value="-1"] {
	border-bottom: 1px solid black;
	padding-bottom: 2px;
}

To me, this little hackery is worth the convenience and correctness of HasSelectedValue.

HasSelectedValues (plural) and SelectManyListBox are left as an exercise to the reader (for now, anyway).

Enjoy!

Advertisements

Posted in Google Web Toolkit, Model-View-Presenter | 15 Comments »

Quick note on using gwt-presenter’s ActionException

Posted by David Chandler on December 9, 2009

It seems that the best way to use gwt-presenter‘s ActionException is to extend it, as exception chaining using ActionException does not appear to work. Here’s a working example:

package com.roa.common.exception;

import net.customware.gwt.dispatch.shared.ActionException;

public class UserNotLoggedInException extends ActionException
{
	private String loginUrl;

	// Required for GWT-RPC!
	private UserNotLoggedInException()
	{
		super();
	}

	public UserNotLoggedInException(String loginUrl)
	{
		super();
		this.loginUrl = loginUrl;
	}

	public String getLoginUrl()
	{
		return loginUrl;
	}
}

Extending ActionException is nice because all your handler execute methods already declare it. And this way, in client code, you can use instanceof in your exception handlers without the need for getCause(), checking for null, etc.

Thanks to the Apache Hupa mail project for a similar example (InvalidSessionException) that helped me see the light on this! While you’re checking out Hupa, have a look at the HupaCallback class, too. Pretty nifty way to achieve centralized error handling on the client combined with gwt-presenter’s DisplayCallback class.

Posted in Google Web Toolkit, Model-View-Presenter | Leave a Comment »

An MVP-compatible EnumListBox for GWT

Posted by David Chandler on December 7, 2009

A frequent request on the GWT and gwt-presenter forums is for a ListBox that implements HasValue like a TextBox. I recently needed one myself, and thought it would be especially cool if I could use it with a Java enum type like this:

	public static enum Frequency {DAILY, WEEKLY, MONTHLY};

	private ConstantsWithLookup enumLabels = GWT.create(EnumLabels.class);
	private EnumListBox<Frequency> freqBox;

	freqBox = new EnumListBox<Frequency>(Frequency.class, enumLabels);

In keeping with MVP philosophy, the presenter’s display interface only needs the HasValue type to get and set the selected value as well as add a ValueChangeHandler to respond to a new selection. Here as some relevant excerpts from a presenter that uses the EnumListBox:

	public interface Display extends WidgetDisplay
	{
		HasValue<Frequency> getFrequency();
	}
	...
	protected void onFirstRequest()
	{
		...
		display.getFrequency().addValueChangeHandler(new ValueChangeHandler<Frequency>()
		{
			@Override
			public void onValueChange(ValueChangeEvent<Frequency> event)
			{
				// Do something with the newly selected event.getValue()
				...
			}
		});
	}

Here’s a straightforward implementation of an EnumListBox that implements HasValue. Thanks to the gwt-ent project for the original idea for this.

package com.roa.app.client.ui.widget;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.ConstantsWithLookup;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.ListBox;
import com.roa.common.client.util.EnumTranslator;

public class EnumListBox<T extends Enum<T>> extends ListBox implements HasValue<T>
{

	private final Class<T> clazzOfEnum;
	private boolean valueChangeHandlerInitialized;

	public EnumListBox(final Class<T> clazzOfEnum, final ConstantsWithLookup constants)
	{
		if (clazzOfEnum == null)
			throw new IllegalArgumentException("Enum class cannot be null");

		this.clazzOfEnum = clazzOfEnum;
		EnumTranslator enumTranslator = new EnumTranslator(constants);

		T[] values = clazzOfEnum.getEnumConstants();

		for (T value : values)
		{
//			this.addItem(constant.toString(), constant.name());
			this.addItem(enumTranslator.getText(value), value.name());
		}
	}

	public T getSelectedValue()
	{
		if (getSelectedIndex() >= 0)
		{
			String name = getValue(getSelectedIndex());

			T[] values = clazzOfEnum.getEnumConstants();
			for (T value : values)
			{
				if (value.name().equals(name))
					return value;
			}
		}

		return null;
	}

	public void setSelectedValue(T value)
	{
		T[] values = clazzOfEnum.getEnumConstants();
		for (int i = 0; i < values.length; i++)
		{
			if (values[i] == value)
			{
				this.setSelectedIndex(i);
				return;
			}
		}
		throw new IllegalArgumentException("No index found for value " + value.toString());
	}

	/*
	 * Methods to implement HasValue
	 */

	@Override
	public T getValue()
	{
		return this.getSelectedValue();
	}

	@Override
	public void setValue(T value)
	{
		this.setValue(value, false);
	}

	@Override
	public void setValue(T value, boolean fireEvents)
	{
		T oldValue = getValue();
		this.setSelectedValue(value);
		if (fireEvents)
		{
			ValueChangeEvent.fireIfNotEqual(this, oldValue, value);
		}
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<T> handler)
	{
		// Initialization code
		if (!valueChangeHandlerInitialized)
		{
			valueChangeHandlerInitialized = true;
			super.addChangeHandler(new ChangeHandler()
			{
				public void onChange(ChangeEvent event)
				{
					ValueChangeEvent.fire(EnumListBox.this, getValue());
				}
			});
		}
		return addHandler(handler, ValueChangeEvent.getType());
	}

}

There’s really not much to it, just a little weirdness that always comes with generics. Notice that the constructor uses an EnumTranslator to populate the labels in the ListBox. This allows you to use a standard GWT ConstantsWithLookup inteface to supply localized text for the enum values instead of the constant names. ConstantsWithLookup is just like Constants, but with the important ability to find a value dynamically without invoking a method corresponding to the property name. Unfortunately, you still have to define a method for each value of the enum in your ConstantsWithLookup class, even though it’s never used directly. Here’s a sample interface:

public interface EnumLabels extends ConstantsWithLookup {
	// Enums
	String com_mypackage_MyClass_Frequency_DAILY();
	String com_mypackage_MyClass_Frequency_WEEKLY();
	String com_mypackage_MyClass_Frequency_MONTHLY();
	String com_mypackage_MyClass_Frequency_QUARTERLY();
	String com_mypackage_MyClass_Frequency_YEARLY();

And the corresponding default properties file EnumLabels.properties:

com_mypackage_MyClass_Frequency_DAILY=daily
com_mypackage_MyClass_Frequency_WEEKLY=weekly
com_mypackage_MyClass_Frequency_MONTHLY=monthly
com_mypackage_MyClass_Frequency_QUARTERLY=quarterly
com_mypackage_MyClass_Frequency_YEARLY=yearly

And finally, here’s my EnumTranslator:

package com.roa.common.client.util;

import com.google.gwt.i18n.client.ConstantsWithLookup;

/**
 * Does a properties file lookup to get text associated with an enum value
 * Property keys use the full class name with all dots and dollars
 * converted to underscores. Keys are case-sensitive and GWT requires a
 * method in the interface that extends ConstantsWithLookup, even though
 * the method is never called.
 *
 * Example:
 * String my_package_class_Frequency_DAILY();
 *
 * In the corresponding properties file:
 * my_package_class_Frequency_DAILY=daily
 *
 * @author David Chandler
 */
public class EnumTranslator
{
	private ConstantsWithLookup constants;

	public EnumTranslator(ConstantsWithLookup constants)
	{
		this.constants = constants;
	}

	public String getText(Enum e)
	{
		String lookupKey = e.getClass().getName() + "." + e.name();
		lookupKey = lookupKey.replace(".", "_");
		lookupKey = lookupKey.replace("$", "_");
		return constants.getString(lookupKey);
	}
}

This EnumListBox is a fairly hard-wired kind of ListBox. In the near future, I anticipate refactoring along these lines:

  1. Add a constructor that takes any java.util.List, not just an Enum.
  2. Create an interface HasSelectedValue that extends HasValue by adding a populateAllSelections() method. This would allow the available selections to come from the presenter through the Display interface and is thus even better for MVP. Versions of the new method could also take a java.util.List or Enum and would replace the constructor.
  3. Ditto for a HasSelectedValues interface to deal with multiple-select type ListBoxes.

Stay tuned.

	...

Posted in Google Web Toolkit, Model-View-Presenter | 11 Comments »

How to reduce startup time with gwt-presenter

Posted by David Chandler on November 24, 2009

I’ve finally figured out a way to trim down the initial load time for my app. I’m not quite ready for GWT 2, runAsync(), or the new Place API in gwt-presenter, but I’ve been able to cut my initial load time significantly (from 14s to 2s) by doing some lazy loading within my presenters and views. In a nutshell, here’s how it works:

  • I now do nothing in the constructor and bind() methods of each presenter and view.
  • Instead, I’ve created a new method onFirstRequest() in my base presenter. It gets called on the first invocation of onPlaceRequest(), which simply increments a counter in a class field to keep track.
  • I’ve added an init() method to the base presenter’s Display interface. It gets called by onFirstRequest(). I moved all widget creation in my views from the constructor and onBind() methods into this init() method instead, thus delaying all widget creation until the first time the view is accessed.
  • Following a suggestion from Per Wiklander in a recent comment to this blog, I noop’d the addWidget() method in my WidgetContainerDisplay class. This method gets called for each presenter that you add to a WidgetContainerPresenter, which doesn’t make sense for the way I’m using the container (I show only one view at a time). The addWidget() method is not used for anything else.

Since this particular scheme utilizes onPlaceRequest() to keep track of the first invocation, it will only work if you first reveal a view by firing the corresponding PlaceRequentEvent, either in code or by visiting the place URL.

Posted in Google Web Toolkit, Model-View-Presenter | 6 Comments »

Writing common test data services for gwt-dispatch with Guice

Posted by David Chandler on October 28, 2009

The way it stands now after my last several posts on unit testing is that each test method in a JUnit TestCase runs its own context, including its own PersistenceManager injected with Guice. Because I’m initializing the AppEngine test environment with LocalDatastoreService.NO_STORAGE_PROPERTY = TRUE, any test data I create in one test is not available to the next test method, even in the same TestCase class. This is typical behavior for JUnit test cases, and generally a good thing as each test should be independent, but it does mean we need a convenient way to create test data. My current strategy is twofold:

  1. Create test data used by all tests in the TestCase setUp() method that runs before each test
  2. Create common test data (used by multiple TestCases) in test data generator services

The first problem to solve is how to get access to a dispatch service and PersistenceManager inside the test data generators. Both are now being injected by Guice as covered in previous posts, so I’ve written a BaseTestDataService that does the Guice magic:

package com.roa.test.service;

import net.customware.gwt.dispatch.client.standard.StandardDispatchService;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.roa.server.guice.ServerModule;
import com.turbomanage.gwt.server.PMF;
import com.turbomanage.gwt.server.guice.DispatchTestModule;

public class BaseTestDataService
{
	protected static Injector inj = Guice.createInjector(new ServerModule(),
		new DispatchTestModule());;

	protected static StandardDispatchService getService()
	{
		return inj.getInstance(StandardDispatchService.class);
	}

	protected static PMF getPMF()
	{
		return inj.getInstance(PMF.class);
	}
}

I’m intentionally using a static getPMF() method to make it as simple as possible to use the test data services in a unit test via static methods. Alternatively, I could have used instance methods and constructor injection, but then you’d have to create a new instance of a test data service in each test, which is just that much more code to write… Also, constructor injection is not possible in this case because the TestCases themselves are not instantiated by Guice, so instantiating a new test data service from a test case would not involve Guice, either.

It does not matter that the BaseTestDataService and BaseTest (below) are both calling Guice.createInjector() and thereby creating multiple Guice contexts, each having its own PMF instance. The important thing for these database tests is that they’re all going against one Datastore, not one PersistenceManager.

Here’s a simple test data generator that extends BaseTestDataService and provides a method to add a test user:

package com.roa.test.service;

import com.roa.client.domain.User;
import com.roa.shared.rpc.AddUserAction;
import com.roa.shared.rpc.AddUserResult;

public class UserTestDataService extends BaseTestDataService
{
	public static User addTestUser() throws Exception
	{
		// Create new user
		User u = new User();
		u.setEmailAddress("test@example.com");
		u.setFirstName("Test");
		u.setLastName("User");
		u.setGoogleAccountId("testAccountId");
		AddUserResult userResult = (AddUserResult) getService().execute(
			new AddUserAction(u));
		u = userResult.getUser();
		return u;
	}
}

Note the call to getService() on line 17. Thanks to Guice, test data generator services can invoke gwt-dispatch ActionHandlers the same way as the tests themselves.
Finally, here’s a test case that calls the above service to create a test user in the Datastore:

package com.roa.test;

import java.util.List;

import javax.jdo.Query;

import com.appenginefan.toolkit.unittests.BaseTest;
import com.roa.client.domain.User;
import com.roa.test.service.UserTestDataService;

public class UserTestCase extends BaseTest
{

	@Override
	protected void setUp() throws Exception
	{
		super.setUp();
		UserTestDataService.addTestUser();
	}

	public void testUserAdded() throws Exception
	{
		// Run tests here
		Query q = pm.newQuery(User.class, "emailAddress == e");
		q.declareParameters("java.lang.String e");
		List<User> users = (List<com.roa.client.domain.User>) q.execute("test@example.com");
		assertEquals(1, users.size());
		User user = users.get(0);
		assertNotNull(user.getId());
	}
}

I should probably show my BaseTest method, too. I’m using AppEngineFan’s BaseTest as discussed in previous posts and modified the setUp() method for Guice injection as follows:

	/**
	 * Sets up the App Engine environment.
	 */
	@Override
	protected void setUp() throws Exception
	{
		if (initializer != null)
		{
			throw new UnsupportedOperationException(
				"setup may only be called once!");
		}
		super.setUp();
		initializer = new TestInitializer(getEnvironmentOrNull());
		initializer.setUp();
		Injector inj = Guice.createInjector(new ServerModule(),
			new DispatchTestModule());
		this.testSvc = inj.getInstance(StandardDispatchService.class);
		this.pm = inj.getInstance(PMF.class).getPersistenceManager();
	}

Thanks to Guice, we can now get access to the PersistenceManager and call ActionHandlers via a dispatch test service even from static methods in test data generators. This greatly streamlines unit testing.

Posted in AppEngine, GIN / Guice, Model-View-Presenter | Leave a Comment »

More on unit testing with an injected JDO PersistenceManager

Posted by David Chandler on October 27, 2009

Regarding my previous post, it turns out that I needed a TestPMF implementation sooner than I thought. The reason is the way I’m injecting a DispatchTestService in my unit tests (as described in this post). I’m calling createInjector() in the setUp() method, which gets run before each test method:

	@Override
	protected void setUp() throws Exception
	{
		super.setUp();
		Injector inj = Guice.createInjector(new ServerModule(),
			new DispatchTestModule());
		testSvc = inj.getInstance(StandardDispatchService.class);
		// This pm is needed only for code in this class that calls a PM directly
		// ActionHandlers are injected with the PMF singleton from Guice
		pm = inj.getInstance(PMF.class).getPersistenceManager();
	}

Since setUp() gets called before each test method, Guice is initialized for each test method, and therefore Guice calls the constructor for my DefaultPMF class for each test method. Repeated from the previous post, the DefaultPMF class looks like:

package com.turbomanage.gwt.server;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;

public final class DefaultPMF implements com.turbomanage.gwt.server.PMF
{
	private final PersistenceManagerFactory pmfInstance = JDOHelper
			.getPersistenceManagerFactory("transactions-optional");

	public DefaultPMF()
	{
	}

	@Override
	public PersistenceManager getPersistenceManager()
	{
		return pmfInstance.getPersistenceManager();
	}
}

Because DefaultPMF creates a named PersistenceManagerFactory, JDO complains that the named PersistenceManagerFactory has already been created. My solution for now is to replace the DefaultPMF with a TestPMF that uses a Properties map to initialize the PersistenceManager, just as the AppEngineFan TestInitializer does. Here’s a working TestPMF:

package com.turbomanage.gwt.server;

import java.util.Properties;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;

public class TestPMF implements PMF
{
	private final PersistenceManagerFactory pmf;

	public TestPMF()
	{
		Properties newProperties = new Properties();
		newProperties
			.put("javax.jdo.PersistenceManagerFactoryClass",
				"org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory");
		newProperties.put("javax.jdo.option.ConnectionURL", "appengine");
		newProperties.put("javax.jdo.option.NontransactionalRead", "true");
		newProperties.put("javax.jdo.option.NontransactionalWrite", "true");
		newProperties.put("javax.jdo.option.RetainValues", "true");
		newProperties.put("datanucleus.appengine.autoCreateDatastoreTxns",
			"true");
		newProperties.put("datanucleus.appengine.autoCreateDatastoreTxns",
			"true");
		pmf = JDOHelper.getPersistenceManagerFactory(newProperties);
	}

	@Override
	public PersistenceManager getPersistenceManager()
	{
		return pmf.getPersistenceManager();
	}

}

Now simply bind PMF to its TestPMF implementation in your Guice module for tests (DispatchTestModule in the setUp() method above), and each unit test method will run with a freshly created PersistenceManager.

Posted in AppEngine, GIN / Guice, Model-View-Presenter | 1 Comment »

Unit testing with JDO PersistenceManager injected via Guice

Posted by David Chandler on October 26, 2009

This is a follow-up to last week’s post on unit testing ActionHandlers with Guice. David Peterson pointed out on the gwt-dispatch mailing list that I could inject a PersistenceManager into my ActionHandlers in order to provide an alternate PersistenceManager for unit testing. I don’t actually need an alternate PM yet as it is handled transparently by my AppEngine test environment, but I thought it would be easier to do it sooner rather than later, so here goes.

I’ve created an interface called PMF (in order to avoid confusion with JDO’s PersistenceManagerFactory).

package com.turbomanage.gwt.server;

import javax.jdo.PersistenceManager;

public interface PMF
{
	PersistenceManager getPersistenceManager();
}

My default PMF implementation works exactly the same as before:

package com.turbomanage.gwt.server;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;

public final class DefaultPMF implements com.turbomanage.gwt.server.PMF
{
	private final PersistenceManagerFactory pmfInstance = JDOHelper
			.getPersistenceManagerFactory("transactions-optional");

	public DefaultPMF()
	{
	}

	@Override
	public PersistenceManager getPersistenceManager()
	{
		return pmfInstance.getPersistenceManager();
	}
}

The DefaultPMF gets bound in my Guice ServerModule:

	@Override
	protected void configureHandlers()
	{
		...
		bind(PMF.class).to(DefaultPMF.class).in(Singleton.class);
		...
	}

And finally, the PMF is injected into an ActionHandler:

public class AddUserHandler implements
	ActionHandler<AddUserAction, AddUserResult>
{
	@Inject
	private PMF pmf;
	private PersistenceManager pm;

	@Override
	public AddUserResult execute(AddUserAction action, ExecutionContext context)
		throws ActionException
	{
		this.pm = pmf.getPersistenceManager();
		...
	}
	...
}

Now, when the need arises for a test implementation of PMF, I can easily bind a different implementation in my Guice TestModule as shown in the earlier post.

Update: I did not test this thoroughly before I posted, and the need for a TestPMF arose just hours later. See my next post for the solution.

Posted in AppEngine, GIN / Guice, Model-View-Presenter | 1 Comment »

How to show a “Loading…” pop-up in your GWT app

Posted by David Chandler on October 22, 2009

Last week, I posted a technique for displaying a splash screen before GWT loads. In this post, we’ll look at a way to show a modal pop-up after your app is up and running, but while GWT is making AJAX calls.

The basic idea is to show and center a pop-up with some text and an Ajax wait image. There are a couple ways to hook it into gwt-presenter. The WidgetDisplay interface method has startProcessing() and stopProcessing() methods that get called by the DisplayCallback class that you pass to dispatch.execute(). If you want to show the pop-up for only one presenter, then you can simply implement these methods in your view. More likely, however, a centered pop-up will be used by multiple presenters, in which case we can create an AppLoadingPresenter and AppLoadingView that will listen for an AppLoadingEvent. Any presenter or service can then fire the AppLoadingEvent to cause the “Loading…” panel to be shown. Here’s some very elegant code courtesy of my co-worker Tony Richardson. I’ll leave it up to you to create the AppLoadingEvent and fire where you need it. One more note: I’m reusing the AppLoadingEvent to trigger both showing and hiding the pop-up by means of a boolean argument in the AppLoadingEvent constructor. It might be more correct to use separate events for this, but it’s getting late…

package com.roa.client.presenter;

import java.util.List;

import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.place.Place;
import net.customware.gwt.presenter.client.widget.WidgetDisplay;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import com.google.inject.Inject;
import com.roa.client.event.AppLoadingEvent;
import com.roa.client.handler.AppLoadingEventHandler;

public final class AppLoadingPresenter extends
        WidgetPresenter<AppLoadingPresenter.Display>
{
    public interface Display extends WidgetDisplay
    {
        void showWidget();
    }

    private final Display display;
    private final EventBus eventBus;

    @Inject
    public AppLoadingPresenter(Display display, EventBus eventBus)
    {
        super(display, eventBus);
        this.display = display;
        this.eventBus = eventBus;
        bind();
    }

    @Override
    public Place getPlace()
    {
        // We won't really use this presenter as a Place
        return null;
    }

    public void hideLoading()
    {
        this.display.startProcessing();
    }

    @Override
    protected void onBind()
    {
        registerHandler(this.eventBus.addHandler(AppLoadingEvent.TYPE, new AppLoadingEventHandler()
		{
			@Override
			public void onAppLoadingEvent(boolean isComplete)
			{
				if (isComplete)
				{
					display.stopProcessing();
				}
				else
				{
					display.startProcessing();
				}
			}
		}));
    }

    @Override
    public void revealDisplay()
    {
        display.showWidget();
    }
}

And here’s the AppLoadingView. Very simple, but cool effect.

package com.roa.client.ui.web;

import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.roa.client.presenter.AppLoadingPresenter.Display;

public final class AppLoadingView extends PopupPanel implements Display
{
    private final FlowPanel container = new FlowPanel();

    public AppLoadingView()
    {        
        final Image ajaxImage = new Image("path_to_ajax_wait_image");
        final Grid grid = new Grid(1, 2);  
        grid.setWidget(0, 0, ajaxImage);
        grid.setText(0, 1, "Loading...");    
        this.container.add(grid);
        add(this.container);       
    }

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

    @Override
    public void stopProcessing()
    {
        hide();
    }

    @Override
    public void startProcessing()
    {
        center();
        show();
    }

    @Override
    public void showWidget()
    {
        startProcessing();
    }
}

Posted in Google Web Toolkit, Model-View-Presenter | 6 Comments »

Swapping DIVs technique for navigation with gwt-presenter

Posted by David Chandler on October 21, 2009

I have previously written about navigation in gwt-presenter using the DeckPresenter or WidgetContainerPresenter approaches. Those techniques work well for swapping out views in one portion of the page, and could be applied to the whole page, as well; however, here’s another simpler technique for situations in which you need to swap between totally unrelated views. For example, my main app has a header, footer, and content area in which views are swapped out using a WidgetContainerPresenter. However, I also need to replace the whole page (header, footer, and all) for a user registration page. To do this, I simply created two DIVs in the HTML host page:

		<div id="roa-registration"></div>
		<div id="container"></div>

My main AppPresenter loads all the presenters up front and fires a PlaceRequestEvent to the user registration presenter for new users. For existing users, it fires a PlaceRequestEvent based on the URL or to the default presenter if the URL is empty.

...
	public void go(final HasWidgets container)
	{
		this.container = container;
		loadMain();
		hideSplash();
		if (roaModel.getLoginInfo().getUser() != null)
		{
			showMain();
			String currentPlace = History.getToken();
			if ("".equals(currentPlace))
			{
				goToDefaultView();
			}
			else
			{
				// Load requested page
				placeManager.fireCurrentPlace();
			}
		}
		else
		{
			showRegistration();
		}
	}

	private void showRegistration()
	{
		// New user must register
		eventBus.fireEvent(new PlaceRequestEvent(new PlaceRequest(
			UserRegistrationPresenter.PLACE)));
	}

	private void hideSplash()
	{
		DOM.removeChild(RootPanel.getBodyElement(), DOM
			.getElementById(RoaStyles.ID_SPLASH));
	}

	private void loadMain()
	{
		// Hide while loading
		 DOM.setStyleAttribute(RootPanel.get(RoaStyles.CONTAINER_ID)
		 .getElement(), "display", "none");
		container.clear();
		HeaderPanel headerPanel = new HeaderPanel(roaModel.getLoginInfo());
		headerPanel.add(messagePresenter.getDisplay().asWidget());
		container.add(headerPanel);
		...
		container.add(bodyPanel);
		container.add(new FooterPanel());
	}

	private void showMain()
	{
		// Set GWT container visible
		DOM.setStyleAttribute(RootPanel.get(RoaStyles.CONTAINER_ID)
			.getElement(), "display", "block");
		// Load initial data
		prayerListService.refreshPrayerLists();
	}

	private void goToDefaultView()
	{
		// Nothing in URL, load default page
		eventBus.fireEvent(new PlaceRequestEvent(new PlaceRequest(
			ManageListsPresenter.PLACE)));
	}

Finally, I toggle the visibility of the two DIVs in the user registration presenter’s revealDisplay() method, which gets called in response to a PlaceRequestEvent. In addition, I call a hideDisplay() method in the presenter’s onBind() method (called from the constructor), so that its initial state is hidden.

	@Override
	public void revealDisplay()
	{
		super.revealDisplay();
		RootPanel.get(RoaStyles.CONTAINER_ID).setVisible(false);
		RootPanel.get(RoaStyles.REGISTRATION_CONTAINER_ID).setVisible(true);
	}

	public void hideDisplay()
	{
		RootPanel.get(RoaStyles.REGISTRATION_CONTAINER_ID).setVisible(false);
	}

The downside to this technique is that it would be a pain to manage with more than a few DIVs, as each presenter would have to know how to show itself and hide the others; however, for swapping between completely different page layouts, I think it’s easier than creating nested WidgetContainerPresenters (if that would even work). On the plus side, multiple presenters can use each layout (DIV), and most applications are likely to need only a handful of completely distinct page layouts. YMMV.

Posted in Google Web Toolkit, Model-View-Presenter | 8 Comments »

Base presenter and view classes for gwt-presenter

Posted by David Chandler on October 10, 2009

When your presenters extend gwt-presenter’s WidgetPresenter, you are required to implement four methods that are often unused. In order to avoid boilerplate in all my presenters, as well as to do other things that are common to all my presenters, I’ve created an abstract base class that extends WidgetPresenter.

public abstract class MyBasePresenter<D extends
MyBasePresenter.Display> extends WidgetPresenter<D>
{
       public interface Display extends WidgetDisplay
       {

       }

       public MyBasePresenter(final D display, final EventBus eventBus)
       {
               super(display, eventBus);
       }

       @Override
       protected void onBind()
       {
               // TODO Auto-generated method stub

       }

       @Override
       protected void onPlaceRequest(PlaceRequest request)
       {
               // TODO Auto-generated method stub

       }

       @Override
       protected void onUnbind()
       {
               // TODO Auto-generated method stub

       }

       @Override
       public void refreshDisplay()
       {
               // TODO Auto-generated method stub

       }

}

Now instead of extending WidgetPresenter directly, I can extend MyBasePresenter:

public class ManageListsPresenter extends
MyBasePresenter<ManageListsPresenter.Display>
{

       public interface Display extends MyBasePresenter.Display
       {
        ...
       }

       @Inject
       public ManageListsPresenter(final Display display, final EventBus eventBus)
       {
               super(display, eventBus);
               bind();
       }
        ...
}

In similar fashion, I define a corresponding BaseView that eliminates the need for the startProcessing() and stopProcessing() methods required by gwt-presenter’s WidgetDisplay interface. Besides eliminating boilerplate, I use the base view constructor to inject references to my applications Constants and Images singletons (see this previous post):

public abstract class MyBaseView implements MyBasePresenter.Display
{

	protected final RoaConstants constants;
	protected final RoaImages images;

	protected BaseView(final RoaConstants constants, final RoaImages images)
	{
		this.constants = constants;
		this.images = images;
	}

	@Override
	public void startProcessing()
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void stopProcessing()
	{
		// TODO Auto-generated method stub

	}

}

Now all views that extend MyBaseView will have less boilerplate and will automatically have access to the constants and images interfaces.

public class ManageListsView extends MyBaseView implements ManageListsPresenter.Display
{

	@Inject
	public ManageListsView(final RoaConstants constants, final RoaImages images)
	{
		super(constants, images);
        ...
	}
    ...
}

Posted in Google Web Toolkit, Model-View-Presenter | 8 Comments »

 
%d bloggers like this: