TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 now working for Google and residing in Atlanta with the wife of my youth and our five children. My current side project is a not-for-profit startup using GWT on AppEngine. In my "spare" time, I take pictures, preferably of Rocky Mountain National Park.

  • Subscribe

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

    Join 192 other followers

  • Sleepless Nights…

    May 2013
    S M T W T F S
    « Mar    
     1234
    567891011
    12131415161718
    19202122232425
    262728293031  
  • Blog Stats

    • 501,201 hits

Archive for the ‘AppEngine’ Category

Troubleshooting App Engine-connected Android projects with c2dm

Posted by David Chandler on May 18, 2012

Google Plugin for Eclipse has a wizard to create an Android project with App Engine back end including client push (c2dm). The official tutorial is quite good, but after spending the better part of a day trying to get the Cloud Tasks sample up and running again, I thought it might be useful to post a few tips.

General Tips

  • Sign up for c2dm first. Remember the package name and use it when running the Eclipse wizard! The package name is required, and once you choose the package name on c2dm sign-up, it is nowhere visible later. Be patient–it may take an hour or even a day to activate your account.
  • Sign in to Eclipse with the c2dm account name you’ll use (see lower left corner–if not visible, you need Google Plugin for Eclipse). It’s easy to forget this, but Debug As | Local App Engine Connected Project requires you to be signed in.

Run on a Phone With the GAE Dev Server

In this scenario, the phone and dev server must be on the same network! Easiest way is to connect to the same wi-fi router. USB cable does nothing. Be aware that most public wi-fi routers don’t allow devices to contact each other, so it will probably work best at home or on your company’s guest wi-fi network.

  • Ensure that phone and dev server are on the same wi-fi network. Disconnect both from any VPNs.
  • Add -bindAddress 0.0.0.0 to your Web project’s Run Configuration | Program Arguments. This will start the server listening on all addresses, not just the default localhost (which the phone can’t see).
  • When you choose Debug As | Local App Engine Connected Android Application, GPE hardcodes your machine’s IP address in assets/debugging_prefs.properties. This is where the Android app looks up the address of the server.
  • You can launch/debug the Android app and the Web app independently; however, if your server IP address changes, you must again Debug As | Local App Engine Connected Android Application in order to update the IP address in assets/debugging_prefs.properties.
  • In case you wondered, the Android and Web projects are associated in a file in the Android project. You can find it in .settings/com.google.gdt.eclipse.mobile.android.prefs. To associate a different App Engine project with an Android project, simply edit this file and refresh the project.
  • If you’re using the GWT dev mode browser plugin, you can still connect to 127.0.0.1. If you connect to the address shown in Development Mode tab (your machine’s network IP address), you may need to allow the address in the dev mode browser plugin. Click the GWT icon in the address bar to do this.
  • Make sure you log in to the Web app as the c2dm user, not the default test@example.com.

Run on a Phone Against the Production App

In the production scenario, you’re using real c2dm so the phone doesn’t have to be on wi-fi at all.

  • Edit Setup.java and change APP_NAME and SENDER_ID to match your GAE app id and c2dm account.
  • Change app id in appengine-web.xml to match your GAE app.
  • Deploy to App Engine with your c2dm account.
  • Force sign in to GAE app by going to [prod_url]/tasks/. This triggers the security constraint in web.xml to get logged in to GAE. After logging in, you’ll get an error page, but that’s OK. Then go to [prod_url]/ and Say Hello to App Engine. If logged in, you should see a success message.
  • If you’ve previously connected an account on a phone to this production app, go to GAE datastore viewer and delete all records.
  • In Eclipse, Debug as | Remote App Engine Connected Android project
  • On the phone, you’ll be prompted to connect an account. Use your c2dm account. If you have previously connected a different account, go to Menu | Accounts | Disconnect in the app and reconnect.

The CloudTasks project still has a few issues. Feel free to log them in the tracker.

Posted in Android, AppEngine, Google Web Toolkit | 7 Comments »

App Engine, Dart, and Android at DevNexus

Posted by David Chandler on March 23, 2012

DevNexus keynote

DevNexus keynote

First, a huge thank you to the volunteer organizers and sponsors of DevNexus! The Atlanta JUG‘s annual not-for-profit conference attracted 500 mostly Java developers this year and remains one of the best values of any developer conference in the world.

I gave an update on Google App Engine for Java (see slides) and a pitch for HTML5 + Dart (see slides).

There were a lot of talks on mobile / Web development this year, including:

  • JQuery Mobile framework (Raymond Camden, Adobe)
  • Intro to PhoneGap (Raymond Camden, Adobe)
  • Java-Powered Mobile Cross-Platform Mobile Apps with Phone Gap (Andrew Trice)
  • Web vs. Apps keynote (Ben Galbraith)
  • Easy Mobile Development: Intro to Appcelerator Titanium (Pratik Patel)
  • What’s New in Android (Robert Cooper)
  • Spring for Android (Roy Clarkson, Spring)
  • Mind-Blowing Apps with HTML5 Canvas (David Geary)

All the mobile / Web talks that I attended were standing room only (70-130 people, depending on room capacity). It seems that mobile in the enterprise is red hot and enterprise apps are good candidates for Web apps vs. native. I was particularly impressed with

Thanks again to Gunnar, Vince, Sudhir, and the gang for making DevNexus such a high-quality event.

Posted in Android, AppEngine, Dart | 6 Comments »

Will it play in App Engine page moved

Posted by David Chandler on December 21, 2011

Just noticed that the old “Will it play in App Engine Java” page has moved to the appengine wiki. This was necessary because Google Groups deprecated groups pages. It’s also very out of date.

Posted in AppEngine | 1 Comment »

App Engine code download saves the day

Posted by David Chandler on August 26, 2011

While I was working on the sample project for yesterday’s post, I accidentally deleted the src and target folders in my project. I’m not entirely sure how this happened, but my source files were neither in the Trash folder nor Eclipse local history (except for the Maven POM, which I had just been working on). I was just getting ready to check into SVN but hadn’t done it yet, so it was beginning to look like a total loss.

Fortunately, I had just deployed my project to App Engine, which now allows you to download your deployed application. Java sources don’t get deployed so I had only WEB-INF/classes to work with, but a quick trip through JAD recovered the sources also (albeit sans comments–sorry about that, folks). I like this new GAE feature. In the future, I’ll at least create a local git repo before I start mucking with the Eclipse Run configs…

Posted in AppEngine | 1 Comment »

Using the GAE App Identity API and OAuth2

Posted by David Chandler on August 25, 2011

One of the challenges of cloud computing is interoperability: how can an application hosted on one cloud service authenticate and communicate with another cloud app or service? Within the enterprise, IT departments often utilize a central identity store like PingFederate from Ping Identity. How to manage identities in the cloud, however?

Google App Engine recently unveiled one solution: the Application Identity API, which provides your app with public key infrastructure managed by Google. Each App Engine app has a unique identity in the form of an email address and public/private key pairs which are rotated every few hours. The API lets your app discover its own identity, obtain the current public keys, and sign an object using the private key. The beauty of the API is that you the developer don’t have to manage the keys at all. Google handles all the PKI, crypto, rotation, and security.

Recently, at the Cloud Identity Summit sponsored by Ping Identity, I presented an example of using the Application Identity API to connect from App Engine to Google Storage as part of a 3-hr workshop on Integrating with the Google Cloud (see slides 149-153). I’ve now published a sample project showing how a GAE app can authenticate to the Google Storage API using OAuth2 and the App Identity API.

How to call Google Storage API from App Engine Java

Let’s say you’ve created a Google Storage account (free within limits) and want to access it from your Java code in App Engine. First, you need to set up your Google Storage account appropriately:

  1. Add your GAE app’s unique ID (aka “robot” email address) to Team in Google APIs Console.
    • to find it, call ApplicationIdentityService.getServiceAccountName() in your GAE app
    • assign write or owner access
    • use in bucket ACLs also
  2. Note your Google Storage project ID (click Google Storage in the left nav of the Google APIs Console)

Now in your Java code, you’ll

  1. Obtain your app’s unique ID with ApplicationIdentityService.getServiceAccountName()
  2. Create a JWT token with issuer ID = your app’s unique ID
  3. Sign it with ApplicationIdentityService.signForApp()
  4. Exchange it for an OAuth token by calling Google’s OAuth endpoint (which, in turn, calls App Engine infrastructure to verify your app’s identity).
  5. Include the OAuth token with each request to Google Storage API

Two different sample projects illustrate how to do this. You might want to start with GoogleStorageImpl.java showing all the low-level calls to create a JWT token and exchange it for an authentication credential.

Once you understand how it works, you can extend AbstractTwoLeggedFlowServlet to handle the token exchange for you. This is the approach I’ve taken in the App Identity Sample with OAuth2 and Google Storage. As an aside, the Maven POM in this project is a good starting point if you’re looking to call Google APIs from Java. There are lots of jars associated with Google APIs Client Library for Java available in Maven Central, and it can be confusing to figure out which ones are really needed.

Note: the sample projects above will only work if you actually deploy the code to App Engine. Google’s OAuth2 endpoint only works with production infrastructure (not your local dev server).

This article is about application identity, but if you’re also interested in user identity, be sure to check out the Google Identity Toolkit, which makes it easy for you to support login to your app from other identity providers (Yahoo, Hotmail, AOL).

Resources

Posted in AppEngine | 11 Comments »

Sending HTML emails with App Engine and Velocity in a Maven project

Posted by David Chandler on July 6, 2011

I’ve been using the App Engine Mail API for a while now to send emails in plain text format, but recently decided to beef it up to allow HTML formatting. In addition, I wanted a template-based approach so I could more easily modify the email contents. To achieve both purposes, I chose Apache Velocity, an easy-to-use, general purpose framework that lets you easily create anything textual from a template (text, email, XML, even Java code once on a previous project).

The main subtlety to observe when using Velocity with App Engine is that by default, Velocity uses the filesystem resource loader to load templates. This works fine in the App Engine development server and should also work in production as long as you put your templates in the WAR. Since my project is using Maven, however, the standard way to do this is to put templates in src/main/resources and let Maven automatically copy them to WEB-INF/classes during the build. In order for Velocity to see them on the classpath, you need Velocity’s ClasspathResourceLoader, so I created a helper class that lazily initializes the Velocity engine with the required resource loader:

/**
 * Singleton that initializes Velocity engine instance with the classpath resource loader
 * 
 * @author David Chandler
 */
public class VelocityHelper {
  private static VelocityEngine velocityEngine;

  static VelocityEngine getVelocityEngine() {
    if (velocityEngine == null)
      init();
    return velocityEngine;
  }

  private static void init() {
    velocityEngine = new VelocityEngine();
    Properties velocityProperties = new Properties();
    velocityProperties.put("resource.loader", "class");
    velocityProperties.put("class.resource.loader.description", "Velocity Classpath Resource Loader");
    velocityProperties.put("class.resource.loader.class",
        "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
    velocityEngine.init(velocityProperties);
  }
}

To use the template, first populate the VelocityContext with variables to be replaced, then merge the template:

VelocityContext context = new VelocityContext();
context.put("date", today);
context.put("username", "johndoe");
VelocityEngine ve = VelocityHelper.getVelocityEngine();
// Finds template in WEB-INF/classes
template = ve.getTemplate("emailTemplate.vm");
StringWriter writer = new StringWriter();
template.merge(context, writer);

Since we’re sending an HTML email, the template is just an HTML file named emailTemplate.vm (by convention–.vm stands for Velocity macro). The template merge substitutes variables like ${date} with their values from the VelocityContext populated above. You can also loop over Collections with #foreach ($item in $list) … #end.

Now let’s send the email. There are a couple things to observe here.

First, webmail readers like Gmail write the HEAD and BODY tags to the page, so the browser will likely ignore these tags in your HTML template. This means you can’t link a stylesheet in the HEAD section of your HTML and expect it to work across email clients. The most compatible approach is to use inline styles, that is, the style=”" attribute on various HTML tags right in your template.

Second, in order to send HTML email, you must set the MIME type correctly. Here is the code that takes the template output, sets the MIME type, and sends the email:

import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.ServletException;

...

Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
try
{
	Message msg = new MimeMessage(session);
	msg.setFrom(from);
	msg.addRecipient(Message.RecipientType.TO, to);
	msg.setSubject(msgSubject);
	if (msgBody.startsWith("<!DOCTYPE html"))
		msg.setContent(msgBody, "text/html");
	else
		msg.setText(msgBody);
	Transport.send(msg);
}
catch (AddressException e)
{
	throw new ServletException(e);
}
catch (MessagingException e)
{
	throw new ServletException(e);
}

That’s it in a nutshell. Spam away…

/dmc

Posted in AppEngine | 6 Comments »

Configuring the App Engine development server

Posted by David Chandler on June 30, 2011

Last week, I posted a way to preserve the local Datastore when using Maven by setting a system property datastore.backing_store=path. Although it’s not explicitly documented, it appears that many dev mode services can be configured this way. The configuration flags are documented with the local unit testing Javadocs like this one for LocalDatastoreService. Click on the property, then the link to Constant Field Values to find the associated String you can use in a -D argument as shown in last week’s post. Note that unit tests can configure services directly by calling setters on the test helper like LocalDatastoreServiceTestConfig.

Happy tweaking…

Posted in AppEngine | Leave a Comment »

Preserving the Datastore when using App Engine dev server with Maven

Posted by David Chandler on June 25, 2011

Problem

I’m currently working on a GWT+GAE Maven project and the local datastore gets wiped every time I start the dev server, whether using mvn clean gae:run or Google Plugin for Eclipse.

Cause

Per the official dev server doc, the local datastore is stored in WEB-INF/appengine-generated/local_db.bin. For most Maven projects, the WEB-INF directory is located under target/${project.build.finalName}, so local_db.bin is under the target directory, which gets wiped every time you mvn clean. It also gets wiped when launching dev mode with Google Plugin for Eclipse.

Solution

Specify an alternate path to the dev server datastore.

In Eclipse, edit the project’s Run Configuration and add this to the VM args:

-Ddatastore.backing_store=${project_loc}/local_db.bin

This will put the local datastore in the project root directory, where it won’t get wiped every time you launch the dev server.

In the project’s POM, add this to the configuration section for maven-gae-plugin:

<jvmFlags>
	<jvmFlag>-Ddatastore.backing_store=${project.basedir}\local_db.bin</jvmFlag>
</jvmFlags>

Many thanks to Marcel Overdijk for pointing the way on the maven-gae-plugin group.

Posted in AppEngine | 2 Comments »

Are Private Clouds Really Safer?

Posted by David Chandler on June 24, 2011

For the second time in two weeks (first in Detroit, then in Atlanta), I’ve listened to a panel discussion on cloud computing in which a panelist has claimed that private clouds are safer than “The Cloud.” In both cases, the panelist was a data center vendor (hmmm…) and in both cases, the other panelists were not so readily agreed. The vendor rep in Atlanta kept mentioning the possibility of network sniffing, as though someone might be able to penetrate Amazon’s hardware virtualization, gain access to the real Ethernet controller, put it in promiscuous mode, and then sniff traffic on … the one wire running to the switch?

Bob Reid of the kotter group asked the best question of the evening: is there any empirical evidence that public cloud computing is safer than private cloud? In other words, has anyone ever successfully penetrated Amazon’s hardware virtualization, App Engine’s VM, etc. and used it to obtain other customers’ data? Said data center vendor acknowledged that social engineering is a much more likely attack vector and can be used just as successfully in a private cloud as public, but then repeated his concerns about the public cloud without citing any evidence. Thankfully, Dennis Hurst, founder of the Cloud Security Alliance, nailed it: the studies show that most break-ins are due to application design flaws and have nothing to do with the hosting environment.

There’s no doubt that some CxOs get a warm fuzzy from knowing that their data is on “their own” servers; however, this would appear to be a false sense of security. If anything, public cloud providers are safer (Dennis Hurst alluded to this earlier in the discussion) because security is an inherent design consideration. All public cloud providers rely on some form of virtualization, whether at the hardware layer (AWS) or a Java VM with security restrictions like App Engine and no doubt do continuous testing to ensure the security of the virtualization layer. The strength of the security sandbox is fundamental to the offering, and public cloud providers can afford to employ the best and brightest to get it right (unlike regional data center vendors–are you sure you’ve got the latest patches?).

Furthermore, public cloud offerings are typically built around services like AWS’s SimpleDB and App Engine’s Datastore, which are not subject to attacks like SQL injection because the service APIs don’t allow you to execute arbitrary database commands. Service APIs significantly limit attack surface, which is one reason why I prefer App Engine’s approach to virtualization over Amazon’s (granted, I’m a little biased). With AWS, you’re still responsible to configure your virtual machine instances correctly, albeit you have to explicitly open network ports so you’re not wide open by default.

The question, I think stands: is anyone aware of an incident in which a public cloud customer obtained access to another customer’s data by penetrating the security sandbox? Methinks the cloud offerings of today are generally much safer than the shared Web hosting arrangements of the past because of the superior virtualization technology employed today. Once upon a time, you could use CFFILE on a mis-configured ColdFusion host or similar technique in ASP to gain access to the file system on the shared host. But as far as I know, no one has demonstrated such an exploit against AWS, App Engine, Azure, etc.

Social engineering, insider leaks, and application flaws (which are arguably *less* likely using public cloud services) remain the most likely attack vectors, and CxOs should carefully evaluate FUD from data center vendors before rejecting the public cloud on the basis of security concerns. And while I’m at it, unless a “private cloud” offers elasticity, multi-tenancy, and metered service, I don’t think it can properly be called cloud. Dedicated / colocated hosting has been around for a long time and has its merits, but please don’t “cloud” the vocabulary.

Posted in AppEngine, Web App Security | 1 Comment »

Using GWT RequestFactory with Objectify

Posted by David Chandler on March 25, 2011

I’ve put together a little sample project using GWT’s RequestFactory with Objectify. It’s not very sophisticated, but should get you started.

RequestFactory is a relatively new GWT feature that makes it especially easy to create data-oriented services. In this example, we’ll create a RequestFactory service backed by Objectify to manage arbitrary lists of items such as a ToDo list, grocery list, etc.

Domain Model

First, let’s look at our domain classes (ItemList, ListItem, and AppUser):

ItemList.java

package com.turbomanage.listwidget.domain;

import java.util.List;

import javax.persistence.Embedded;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.turbomanage.listwidget.shared.proxy.ItemListProxy.ListType;

/**
 * POJO that represents a list of items such as a ToDo list.
 * The items are stored as an embedded object.
 */
@Entity
public class ItemList extends DatastoreObject
{
	private String name;
	private Key<AppUser> owner;
	private ListType listType;
	@Embedded
	private List<ListItem> items;
        // Getters and setters omitted
}

DatastoreObject.java:

package com.turbomanage.listwidget.domain;

import javax.persistence.Id;
import javax.persistence.PrePersist;

public class DatastoreObject
{
	@Id
	private Long id;
	private Integer version = 0;

	/**
	 * Auto-increment version # whenever persisted
	 */
	@PrePersist
	void onPersist()
	{
		this.version++;
	}
	// Getters and setters omitted
}

ItemList is an Objectify @Entity. In order for it to work as an entity with RequestFactory, it must have ID and version properties, which are inherited from the DatastoreObject convenience class. Items in the list are stored as an embedded object using the @Embedded JPA annotation supported by Objectify. I could store the items in a separate entity in order to minimize the cost of the query to retrieve just the list names; however, most of the lists will contain only a few items so this serves our example better. Because it is embedded, ListItem is not an entity for purposes of Objectify or RequestFactory, just a simple value type.

ListItem.java:

package com.turbomanage.listwidget.domain;

import java.util.Date;

/**
 * POJO that represents an item in a list.
 */
public class ListItem // POJO
{
	private String itemText;
	private Date dateCreated;
        // Getters and setters omitted
}

AppUser represents a user of our application. It’s an Objectify @Entity and is referenced by the ItemList entity.

package com.turbomanage.listwidget.domain;

import javax.persistence.Entity;

/**
 * An application user, named with a prefix to avoid confusion with GAE User type
 */
@Entity
public class AppUser extends DatastoreObject
{
	private String email;

	public AppUser()
	{
		// No-arg constructor required by Objectify
	}
	// Getters and setters omitted
}

Persistence Layer

The persistence layer on the server side is just a standard ObjectifyDAO that handles all the CRUD operations. It has a static initializer that registers the entity types (ItemList and AppUser–for a later post). ItemListDao extends the generic ObjectifyDao and provides a bit of logic to restrict listAll() to those lists owned by the current user.

ItemListDao.java:

package com.turbomanage.listwidget.server.service;

import java.util.List;

import com.googlecode.objectify.Key;
import com.turbomanage.listwidget.domain.AppUser;
import com.turbomanage.listwidget.domain.ItemList;

public class ItemListDao extends ObjectifyDao<ItemList>
{
	@Override
	public List<ItemList> listAll()
	{
		return this.listAllForUser();
	}

	/**
	 * Wraps put() so as not to return a Key, which RF can't handle
	 *
	 * @param obj
	 */
	public void save(ItemList list)
	{
		AppUser loggedInUser = LoginService.getLoggedInUser();
		list.setOwner(loggedInUser);
		this.put(list);
	}

	public ItemList saveAndReturn(ItemList list)
	{
		AppUser loggedInUser = LoginService.getLoggedInUser();
		list.setOwner(loggedInUser);
		Key<ItemList> key = this.put(list);
		try
		{
			return this.get(key);
		}
		catch (Exception e)
		{
			throw new RuntimeException(e);
		}
	}

	/**
	 * Remove a list. Since items are embedded, they are removed automatically.
	 *
	 * @param list
	 */
	public void removeList(ItemList list)
	{
		this.delete(list);
	}
}

ItemListDao wraps the put() method from ObjectifyDao with a save() method that returns void. This is because put() returns a Key to the newly persisted object, but RequestFactory on the client doesn’t know about about types such as com.googlecode.objectify.Key that exist only on the server (remember that the GWT compiler requires Java source for all types used on the client).

Through the magic of RequestFactory, we can expose ItemListDao directly as a service to be called from the GWT client. This is simpler than GWT-RPC, which requires each service impl to extend RemoteServiceServlet, and much less code than the Command pattern, which typically utilizes Action, Result, and handler classes for each service method (albeit the Command pattern still gives you the most application control over caching, batching, and the like). All that’s needed is a trivial ServiceLocator class which is used by RequestFactory to request an instance of any RequestFactory service.

DaoServiceLocator.java:

package com.turbomanage.listwidget.server.locator;

import com.google.gwt.requestfactory.shared.ServiceLocator;

/**
 * Generic locator service that can be referenced in the @Service annotation
 * for any RequestFactory service stub
 *
 * @author turbomanage
 */
public class DaoServiceLocator implements ServiceLocator {
	public Object getInstance(Class<?> clazz) {
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}
}

Unlike GWT-RPC, RequestFactory services do not directly implement the service interface. As we will see shortly, this is because RequestFactory service interfaces are intended only for the client side and do not use server-side entity types directly. Services do have to provide all the methods in the client-side interface; however, this is enforced via run-time validation, not at compile time as with GWT-RPC. The loss of some compile-time safety is one disadvantage of the RequestFactory approach.

Proxy Interfaces

When using an object-relational mapping framework like Objectify, entities typically contain annotations and other code from the ORM framework for which the Java source is not available to the GWT compiler. Therefore, the same entity representation cannot be used on both client and server. This problem can be partially solved by using the GWT super-src capability to supply a GWT-safe implementation of server-side classes. Objectify does this for its Key type and annotations so the same annotated domain class can be used on both client and server with GWT-RPC, and Gilead offers something similar for Hibernate.

Another approach to the problem is to use the DTO pattern. However, this has two main disadvantages. First, you now have two different representations of each entity class and must manually keep the code in sync. Second, every service call must copy data from the real entity to its client-safe DTO and vice versa. Again, there are frameworks to help with this, but it’s a pain.

The RequestFactory approach solves the entity / DTO problem in a unique way that overcomes the weaknesses of the classic DTO pattern. With RequestFactory, you declare a proxy interface for each entity. Unlike a classic DTO, the proxy interface exposes only method signatures so there are no implementation details to keep in sync. Furthermore, RequestFactory automatically populates client objects from the corresponding entities on the server and vice versa. Here are our proxy interfaces:

ItemListProxy.java:

package com.turbomanage.listwidget.shared.proxy;

import java.util.List;

import com.google.gwt.requestfactory.shared.ProxyFor;
import com.turbomanage.listwidget.domain.ItemList;
import com.turbomanage.listwidget.server.locator.ObjectifyLocator;

@ProxyFor(value = ItemList.class, locator = ObjectifyLocator.class)
public interface ItemListProxy extends DatastoreObjectProxy
{
	// Note: enums work!
	public enum ListType {NOTES, TODO}

	String getName();
	void setName(String name);
	List<ListItemProxy> getItems();
	ListType getListType();
	AppUserProxy getOwner();
	void setListType(ListType type);
	void setItems(List<ListItemProxy> asList);
}

Because ItemList is a Datastore entity with ID and version properties, ListItemProxy extends the EntityProxy interface. The @ProxyFor annotation specifies the domain type on the server, and the locator attribute specifies an entity locator class (see next section). Note that entities can define their own enum types, and they must be declared in the proxy interface, not the entity itself, in order for the enum type to be available on the client.

ListItemProxy.java:

package com.turbomanage.listwidget.shared.proxy;

import java.util.Date;

import com.google.gwt.requestfactory.shared.ProxyFor;
import com.google.gwt.requestfactory.shared.ValueProxy;
import com.turbomanage.listwidget.domain.ListItem;

@ProxyFor(value = ListItem.class)
public interface ListItemProxy extends ValueProxy
{
	String getItemText();
	void setItemText(String itemText);
	Date getDateCreated();
}

ListItem is not an entity. It doesn’t have ID and version properties because it is embedded within the ItemList entity. Therefore, ListItem extends the ValueProxy interface, which can be used for any “value type” (non-entity).

AppUserProxy.java:

package com.turbomanage.listwidget.shared.proxy;

import com.google.gwt.requestfactory.shared.ProxyFor;
import com.turbomanage.listwidget.domain.AppUser;
import com.turbomanage.listwidget.server.locator.ObjectifyLocator;

@ProxyFor(value=AppUser.class, locator=ObjectifyLocator.class)
public interface AppUserProxy extends DatastoreObjectProxy
{
	String getEmail();
}

Finally, AppUserProxy is an entity so it extends EntityProxy.

Generic Entity Locator

RequestFactory requires each entity to provide four Locator methods. These are used by RequestFactoryServlet to obtain an instance of an entity in order to populate it with property values from the client request before invoking the service method. Fortunately, the required methods can be implemented in a separate class which can be shared by all entities. Here is the generic ObjectifyLocator used with all the entities and specified in the @ProxyFor annotation for each entity proxy above.

package com.turbomanage.listwidget.server.locator;

import com.google.gwt.requestfactory.shared.Locator;
import com.googlecode.objectify.helper.DAOBase;
import com.turbomanage.listwidget.domain.DatastoreObject;

/**
 * Generic @Locator for objects that extend DatastoreObject
 */
public class ObjectifyLocator extends Locator<DatastoreObject, Long>
{
	@Override
	public DatastoreObject create(Class<? extends DatastoreObject> clazz)
	{
		try
		{
			return clazz.newInstance();
		} catch (InstantiationException e)
		{
		  throw new RuntimeException(e);
		} catch (IllegalAccessException e)
		{
			throw new RuntimeException(e);
		}
	}

	@Override
	public DatastoreObject find(Class<? extends DatastoreObject> clazz, Long id)
	{
		DAOBase daoBase = new DAOBase();
		return daoBase.ofy().find(clazz, id);
	}

	@Override
	public Class<DatastoreObject> getDomainType()
	{
		// Never called
		return null;
	}

	@Override
	public Long getId(DatastoreObject domainObject)
	{
		return domainObject.getId();
	}

	@Override
	public Class<Long> getIdType()
	{
		return Long.class;
	}

	@Override
	public Object getVersion(DatastoreObject domainObject)
	{
		return domainObject.getVersion();
	}
}

ObjectifyLocator makes use of the fact that all the entities extend DatastoreObject, which defines an ID property of type Long. If your entities don’t extend a common base class or interface, you can still use a generic entity locator by using reflection to call the getId() and getVersion() methods on the underlying entity.

RequestFactory Interface

The heart of RequestFactory is the interface in which you define your services. Each service stub is an interface that extends RequestContext having one or more service methods, and for each service you define an accessor method in the main RequestFactory interface. If you have a small number of services, you can define everything in one class as below.

ListWidgetRequestFactory.java:

package com.turbomanage.listwidget.shared.service;

import java.util.List;

import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.Service;
import com.turbomanage.listwidget.server.locator.DaoServiceLocator;
import com.turbomanage.listwidget.server.service.ItemListDao;
import com.turbomanage.listwidget.shared.proxy.ItemListProxy;

public interface ListwidgetRequestFactory extends RequestFactory
{
	/**
	 * Service stub for methods in ItemListDao
	 * 
	 * TODO Enhance RequestFactory to enable service stubs to extend a base interface
	 * so we don't have to repeat methods from the base ObjectifyDao in each stub
	 */
	@Service(value = ItemListDao.class, locator = DaoServiceLocator.class)
	interface ItemListRequestContext extends RequestContext
	{
		Request<List<ItemListProxy>> listAll();
		Request<Void> save(ItemListProxy list);
		Request<ItemListProxy> saveAndReturn(ItemListProxy newList);
		Request<Void> removeList(ItemListProxy list);
	}
	
	ItemListRequestContext itemListRequest();
}

ItemListRequestContext is a service stub and itemListRequest() is its accessor method. The @Service annotation specifies the implementation class on the server, and the locator attribute specifies a ServiceLocator class from which an instance of the service may be obtained–in this case, our generic DaoServiceLocator shown above.

Service method argument and return types use the proxy interfaces, not the real entity types. Server implementations use the real types and RequestFactory automatically maps between the two. In addition, all service methods return a Request object parameterized with the real return type (or rather, its proxy type). Server implementations return the real entity type directly. Services that have no return type should return Request in the client interface. The disparity between entity types on client and server prevents services from directly implementing the service interface as with GWT-RPC.

Again, note that we’re able to use a DAO directly as our service implementation. Furthermore, as of GWT 2.3, a service can be inherited from a base class (in this case, ObjectifyDao) as per this issue. This is a really powerful capability, as it allows you to implement the common CRUD operations in a single class on the server with no boilerplate code for each service impl. However, on the client side, service stubs cannot yet extend a base interface other than RequestContext, so each service stub must declare methods inherited from a base class as well as those implemented in the service class.

Wiring and Startup

Starting up your RequestFactory service layer in the client is as simple as

private final ListwidgetRequestFactory rf = GWT.create(ListwidgetRequestFactory.class);

In the sample app, I’ve done this in a factory class so it will be available to all presenter classes.

Using RequestFactory

First, let’s look at creating a new ItemList and persisting it to the server. Here is an excerpt from ListsActivity which creates a new instance of ItemListProxy and sends it to the server:

	public void persistList(String listName)
	{
		final ListwidgetRequestFactory rf = this.clientFactory
				.getRequestFactory();
		ItemListRequestContext reqCtx = rf.itemListRequest();
		final ItemListProxy newList = reqCtx.create(ItemListProxy.class);
		newList.setName(listName);
		newList.setListType(ListType.TODO);
		reqCtx.saveAndReturn(newList).fire(new Receiver<ItemListProxy>()
		{
			@Override
			public void onSuccess(final ItemListProxy savedList)
			{
				// Refresh table
				listDataProvider.getData();
				...
			}
		});
	}

Since ItemListProxy is an interface, how can we get an instance of it? By calling the create() method inherited from RequestContext. RequestFactory uses the new AutoBeans framework in GWT, which can be used to create an instance of any interface. Using AutoBeans, RequestFactory registers a visitor object for each setter in order to track all changes to the instance. This is what allows RequestFactory to send only changes to the server with each request.

Once we have an instance of our proxy, we can populate it using its setter methods and call the service method, which returns a Request but doesn’t actually do anything yet. In order to invoke the method on the server, we must fire() the Request and pass it a new Receiver object to handle the callback. Receiver is analogous to GWT-RPC’s AsyncCallback, but is hooked in via the return type (Request) instead of an additional service method argument as with GWT-RPC.

Now let’s look at a query to retrieve all ItemLists. Here is the getData() method from the AsyncDataProvider in ListsActivity that updates the CellTable showing all lists.

		private void getData()
		{
			logger.warning("getting data");
			// To retrieve relations and value types, use .with()
			Request<List<ItemListProxy>> findAllReq = rf.itemListRequest()
					.listAll().with("owner");
			// Receiver specifies return type
			findAllReq.fire(new Receiver<List<ItemListProxy>>()
			{
				@Override
				public void onSuccess(List<ItemListProxy> response)
				{
					updateRowCount(response.size(), true);
					updateRowData(0, response);
				}
			});
		}

The listAll() service call is similar to saveAndReturn() above with one important addition: the with(“owner”) method. This retrieves the related AppUser entity (using its proxy type, of course). The with() method specifies the bean-style name of a property to be populated with the request and is required to retrieve entity properties that are themselves proxy types (EntityType or ValueType), as RequestFactory does not retrieve related entities automatically. You can pass a comma-separated list of property names (“owner,creator,…”) and use dot notation to specify nested objects (“owner.address.city”).

Note: this post isn’t about CellTables, but observe that both updateRowData() and updateRowCount() are required to properly update the table when using an AsyncDataProvider.

Finally, let’s look at an example of updating an object previously returned from the server. Here is an excerpt from EditListActivity:

		public void update(int index, ListItemProxy item, final String newText)
		{
			ItemListRequestContext reqCtx = clientFactory.getRequestFactory()
					.itemListRequest();
			ListItemProxy editItem = reqCtx.edit(item);
			editItem.setItemText(newText);
			editList = reqCtx.edit(editList);
			editList.getItems().set(index, editItem);
			// Save the list since items are embedded
			reqCtx.save(editList).fire(new Receiver<Void>()
			{
				@Override
				public void onSuccess(Void response)
				{
					eventBus.fireEvent(new MessageEvent(newText + " updated",
							MessageType.INFO));
				}
			});
		}

This update() method changes the text of an item in an ItemList and takes an ItemListProxy argument that represents an ItemList previously returned from the server. Before any changes can be made to it, we must call RequestContext.edit() in order to make it mutable and allow RequestFactory to track changes. Then we can getItems(), set the new item text, and save the modified ItemList.

Summary

The combination of RequestFactory and Objectify makes it possible to write a service layer for GWT and App Engine with very little boilerplate code. Hopefully this will help you get started. Comments welcome, as well as contributions to the sample project referenced throughout. Enjoy!

Posted in AppEngine, Google Web Toolkit | 69 Comments »

 
Follow

Get every new post delivered to your Inbox.

Join 192 other followers

%d bloggers like this: