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 231 other followers

  • Sleepless Nights…

    December 2018
    S M T W T F S
    « Nov    
     1
    2345678
    9101112131415
    16171819202122
    23242526272829
    3031  
  • Blog Stats

    • 965,069 hits

Archive for the ‘Google Web Toolkit’ Category

First thoughts on Dart from a GWT developer

Posted by David Chandler on October 10, 2011

I consider myself more of a tools & frameworks guy than a language geek so I’m more likely to groan than gush over a new language for the Web.

However, as I dug into Dart a bit working on a couple of the samples, I have to say I caught a bit of the same fire that I felt when I first encountered Google App Engine and GWT. Dart is fun. Coming from a GWT / Java background, I found it easy to get started.

Here are a few of my favorite things about Dart so far:

  1. Closures. You can register an event handler as simply as
    element.on.click.add((Event e) { window.alert('You clicked'); });
    Already, I don’t miss the clutter of anonymous inner classes.
  2. Functions can be passed by reference. You can define
    myClickHandler(Event e) { ... }
    and then just write
    button.on.click.add(myClickHandler);
  3. Function type aliases are a compact way to create your own callback types.
  4. Optional typing. At first I thought I wouldn’t like this. However, as the Ruby community has long pointed out, Java is full of redundancy. Why write
    String[] values = new String[] {"a","b","c"};
    when
    values = ['a','b','c'];

    will do?
  5. Getters and setters. If you define methods using the get or set keywords, Dart will invoke them when you reference a field using dot notation. That is, some.property automatically invokes some.getProperty();.
  6. Constructor initializers. If an argument has this. before it in a constructor argument list, the field with that name will automatically be initialized with that argument’s value. So a constructor that simply assigns arguments to fields can be written on one line:
    Point(this.x, this.y);
  7. The Dart DOM and HTML libraries provide convenient and mostly transparent access to the DOM. Thus, you can easily use static layout in an HTML file and call document.getElementById(). The Canvas code in the Sunflower and Spirodraw samples is almost identical to the corresponding Javascript.
  8. document.query(id_or_class) and .queryAll() work very similar to jQuery. These are part of the Dart HTML library, which offers convenient access to the DOM.

Thanks to all the syntactic sugar, Dart code is quite a bit smaller than the corresponding GWT app. My GWT sunflower app required very little modification to run in Dart, and the Dart code for the app went from 96 lines to 58 lines. Better still, I replaced the GWT SliderBar widget (almost 1000 lines of Java) with just a few lines of static HTML (my apologies to Firefox users: FF doesn’t support <input type=”range”> yet). Spirodraw was reduced from ~500 lines to ~300 lines, and the control panel layout is completely static HTML, which makes it easier to read.

Of course, it’s very, very early for Dart. GWT is a mature toolkit with a solid IDE (Google Plugin for Eclipse, among others), mature frameworks for RPC, MVP, etc., and a large open source community. But based on first looks, Dart is a promising new way to write Web apps. If browser vendors implement the Dart VM natively, it will rock! Chrome seems pretty likely to do this, at least. Until then, you can use dartc to produce JS for any modern browser. Hopefully, the editor (demo’d in the GOTO conf keynote this morning) will ship soon and make it easy for everyone to get started with Dart.

See also

Advertisements

Posted in Dart, Google Web Toolkit | 9 Comments »

GWT performance tip: watch out for String.split()

Posted by David Chandler on July 12, 2011

GWT benchmarking inside Google shows that due to intentional emulation of the differences between Java and JS regex, GWT’s emulated implementation of String.split() is about an order of magnitude slower than the native split on all browsers. On Chrome, it can be up to 1000x slower (6000 ms vs. 6 ms) if the strings are large enough (>1 MB in benchmark testing). This isn’t likely to be noticeable in many real-world applications, but if you happen to be doing a lot of String manipulation in GWT, you should consider using JS native methods instead.

Posted in Google Web Toolkit | 1 Comment »

Fibonacci fun with GWT

Posted by David Chandler on June 29, 2011

SunflowerI’ve posted a new GWT Canvas demo at gwt-sunflower.appspot.com. Works in all modern browsers and IE>=9. You may need to refresh the page after loading due to a bug in the SliderBar that I haven’t dug into yet.

Like the previous demo, the math provides the fun. Each time you move the slider, the app clears the canvas and draws dots 1…n, where n is the number of seeds shown in the slider. The position of each seed n is computed using the equations in polar form shown above the figure. The key to the geometry is the golden angle (represented by Φ), which is simply the golden ratio as a fraction of a circle, where the golden ratio is approximated by the quotient of two successive Fibonacci numbers (example: 55 / 89 ≈ 0.618). The basic algorithm to fill the seed head (mathematically speaking, not biologically) is a dial going around and around like the hands of a clock, but counterclockwise in this example. Every time the dial reaches a multiple of the golden angle (0.618 x 360° ≈ 222.5°), a seed pops out. The distance of the seed from the center (r) is proportional to the square root of the seed number.

At any given time in the flower’s “growth,” the number of spiral arms apparent at the outer edge is a Fibonacci number (0,1,1,2,3,5,8,13,21,34,…). The number of spiral arms going in the opposite direction is the next nearest Fibonacci number. This property is true of real sunflowers and in fact, most flowers in the daisy family. See, for example, this tiny wildflower I photographed with my “poor man’s macro lens,” an extension tube. The diameter of the flower was less than half the width of my pinky fingernail.

In order to improve graphical performance, the app uses a coordinate space which is only half the actual pixel size (example: 200×200 vs. 400×400). HTML5 Canvas automatically scales the virtual coordinate space to fill the actual pixel space.

Here’s the essential GWT code.

  /**
   * Draw the complete figure for the current
   * number of seeds
   */
  private void drawFrame() {
    front.clearRect(0, 0, maxD, maxD);
    for (int i=0; i<numSeeds; i++)
    {
      double theta = i * PI2 / PHI;
      double r = Math.sqrt(i) * SCALE_FACTOR;
      double x = xc + r * Math.cos(theta);
      double y = yc - r * Math.sin(theta);
      drawSeed(x,y);
    }
  }

  /**
   * Draw a small circle representing a seed centered at (x,y)
   *
   * @param x Center of the seed head
   * @param y Center of the seed head
   */
  private void drawSeed(double x, double y) {
    front.beginPath();
    front.setLineWidth(2);
    front.setFillStyle("orange");
    front.setStrokeStyle("orange");
    front.arc(x, y, SEED_RADIUS, 0, PI2);
    front.fill();
    front.closePath();
    front.stroke();
  }

The entire source code is available via the link below the figure.

Enjoy!

Posted in Google Web Toolkit | 4 Comments »

Google I/O 2011 Highlights

Posted by David Chandler on June 1, 2011

This was my first year at Google I/O, and what a way to start! Besides speaking 3x, I was involved with the GWT Developer Sandbox, GWT Office Hours, and a GWT mini summit the night before I/O for the GWT Developer Sandbox exhibitors and GWT framework authors. The months leading up to I/O were very stressful, but the end result was well worth the effort.

You came for the code

Highly Productive GWT @ I/O 2011The defining moment for me this year was 10:15am Tuesday, the first presentation after the first keynote. This was the moment of truth we’d all been waiting for. People inside and outside Google had been asking for months, “Did I/O sell out in 59 minutes because people just want the free stuff, or did they come for the code?” As I looked over an audience of 300+ people in a room that seated 239 assembled to hear about Highly Productive GWT, the answer was obvious: you came for the code (watch the first 45 sec of the session to hear the audience confirm it).

All of the GWT sessions (filter for Developer Tools track) were packed, many of them standing room only. Besides giving the latest tips on performance and showing off the latest tools, the GWT team demo’d lots of bleeding edge coolness in GWT: mobile development, game programming (hello, disgruntled avians!), and RequestFactory tooling for native Android apps. It was an exciting year for GWT developers.

I/O is more than a clever name

Google I/O is all about the developer community. Despite the mythical status of many, Google engineers and open source contributors are real people, too, and I/O is the premier place to get acquainted, give feedback, and get help. Besides meeting the session speakers, each product team holds Office Hours for 3 hours each day staffed by engineers, where hundreds of folks got their technical questions answered and hob-nobbed with others in the community.

Said one long-time GWT community member:

The discussions I had there were both a great learning experience and an important source of ideas and motivation. Networking with the extended GWT community was very nice. I feel like I could get working right away with Jeff Larsen, Pierre Coirier, Hilbrand Bouwkamp and others whom I only met via forums before the I/O.

I likewise enjoyed meeting many folks in the GWT community whose names you’ll recognize from the GWT group: Philippe Beaudoin and Christian Goudreau (gwt-platform), Pierre Coirier (mvp4g), Stephen Haberman (gwt-mpv), Jeff Larsen, Jeff Schnitzer (objectify-appengine), and many others. How did they all get to I/O, you wonder? Many were invited to take part as speakers or Sandbox exhibitors. Some made it a point to sign up as soon as registration opened, and others engaged in heroic measures (Pierre was one of 10 winners in the Last Call for I/O contest). My own path to I/O was extreme, as it involved getting hired by Google last year 🙂 It was a tremendous privilege to serve one of the most talented and enthusiastic developer communities in the world. Besides meeting well-known participants in the community, I also enjoyed meeting the mostly invisible developers who build with GWT every day, learning about the creative and powerful things you’re doing with GWT, listening to your pain points, etc. In the age of everything digital, there is still no substitute for putting a face to a name and getting the story behind the story.

GWT Developer Sandbox

Besides the GWT sessions and Office Hours, the GWT Developer Sandbox (filter for Developer Tools) was a great place to meet companies using or supporting GWT and to pick the brains of fellow GWT developers. The GWT team selected a wide range of companies to participate this year, from public-facing apps (DayZipping, Broadcastr, LoseIt.com) to B2B (BookedIn, GBST) to enterprise and tools/frameworks (JBoss, Apptio, Vaadin). Check out their Web sites and get some ideas for your own apps. There’s a lot going on in the GWT universe.

Related Product Highlights

I was pretty focused on GWT this year, but there were lots of other exciting announcements and sessions for developers: App Engine backends, full-text search, and Pipeline API (map reduce), all of which I hope to dig into before next year’s I/O. Sessions on PageSpeed and Chrome DevTools are required viewing for Web developers who care about performance and productivity. NFC with Android is a promising new technology for all kinds of apps like mobile payments with Google Wallet. And of course, Chromebooks are expected to greatly accelerate the demand for rich Web apps in the cloud. It’s a great time to be a GWT and App Engine developer!

Geek Fest

Nothing says “happy geeks” like the Google I/O 2011 photos, so I’ll conclude with that. Huge thanks to all the GWT developers who attended this year’s I/O and made it the best GWT event ever!

Posted in Google Web Toolkit | 3 Comments »

Fun with GWT Canvas

Posted by David Chandler on April 29, 2011

One of the things that drew me into programming as a kid was writing simple 2D graphics programs (if you wanted a graphing calculator in those days, you had to write your own). I still remember how excited I was when my junior high math teacher let me write a program on the department’s one and only Apple IIe to graph the rose equation r = cos (nθ). In those days, it took many seconds to draw the figure on screen, which left ample time to reflect on why the number of “petals” on the rose was 2n for even values of n but only n for odd values…

At any rate, one of the reasons I preferred the Apple IIe to my TI-99/4A at home was that the latter had only bitmapped graphics using 8×8 cells, whereas the Apple IIe screen was pixel addressable in a standard x,y grid, just like the 2D canvas in HTML5, which, along with the GWT Canvas wrapper, arrived just in time for the high school Java programming class I’m teaching this year.

My class and I set out to draw equations in polar form but I got carried away when a friend suggested I draw an epitrochoid (it’s the shape of a Wankel engine, thanks for asking). The end result, which uses GWT Canvas and Scheduler (was Timer) may remind you of another childhood toy, but this one doesn’t make any mistakes when the gears slip.

spirodraw.appspot.com

The animation technique used in this demo (as well as the GWT Canvas demo which inspired it) is to obtain a “back” canvas object which is never attached to the DOM. It’s simply never added to the widget hierarchy like the “front” canvas. The rose figure is drawn on the back canvas and accumulates its shape with each frame. The wheels and lines are drawn on the front canvas. To draw each frame, we

  1. Clear the attached (“front”) canvas
  2. Copy the image from the unattached (“back”) canvas forward using Canvas.drawImage()
  3. Draw the wheel / line on the attached (“front”) canvas

The rest is just high school math.

If it runs slowly for you, shrink your browser, as the canvas copy operation take noticeably longer for large canvases. It’s also noticeably faster in Chrome than Firefox, and won’t work in IE until GWT 2.3 (due any day now) adds IE9 support.

If you’re curious about the source, you can find it here:

http://code.google.com/p/konos-java/

Drawing a line with GWT Canvas seems a bit more complicated than it should be, but that’s not GWT’s fault, as it’s just a thin wrapper for the HTML5 Canvas API.

      back.beginPath();
      back.setStrokeStyle(penColor);
      back.setLineWidth(penWidth);
      back.moveTo(lastX, lastY);
      back.lineTo(tx, ty);
      back.closePath();
      back.stroke();

Drawing circles is actually slightly easier because you don’t have to moveTo() the origin first.

        front.beginPath();
        front.arc(wx, wy, Math.abs(r), 0, PI2);
        front.closePath();
        front.stroke();

Oh! I created the GWT color picker using GWT Canvas, too. It’s very compact (no image download) and uses minimal memory because the RGB color values are cleverly (if I do say so myself) mapped to x,y coordinates using the modulus operator. I love math, I really do.

Enjoy!

Posted in Google Web Toolkit | 8 Comments »

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 | 73 Comments »

A (partially) updated SliderBar for GWT 2.2

Posted by David Chandler on March 23, 2011

The GWT team announced a while back that most of the stuff in the GWT incubator would be moving to GWT proper (including the powerful new cell widgets) and the incubator project would no longer be supported. One of my favorite widgets, the SliderBar, has not yet been moved over. It looks like someone has posted an incubator jar for 2.2, but before I realized that, I extracted the SliderBar from the incubator code, simplified the resource packaging a bit, and updated all the deprecated classes to work with 2.2. It’s not implemented as a Cell so probably won’t play nice with CellTables, but it’s otherwise functional. You can find the code in my listwidget sample project.

To use it in your project, just pull in the source or export it as a jar and remember to put the following in your gwt.xml file:

<inherits name='com.google.gwt.gen2.gen2'/>

Happy sliding!

Posted in Google Web Toolkit | 12 Comments »

Working on GWT

Posted by David Chandler on March 18, 2011

Lately, I’ve been working on a GWT patch to enable server-side inheritance in RequestFactory services. Along the way, I’ve picked up a few tips about working on the GWT source itself and thought I’d share them with others who may be interested. (By the way, the Web-based code review tool at the patch link above is used by many teams at Google and is itself an open source project written by Guido vonRossum, creator of python. It runs on App Engine, and is a powerful tool for any open source project).

Check out the GWT source from SVN

> mkdir gwt
> cd gwt
> svn checkout https://google-web-toolkit.googlecode.com/svn/trunk/ trunk
> svn checkout https://google-web-toolkit.googlecode.com/svn/tools/ tools

Import the gwt-dev and gwt-user projects into Eclipse

In Eclipse, go to File | Import | Existing project and browse to gwt/trunk/eclipse. This will find many pre-built projects you can import. Check the boxes to import gwt-dev and gwt-user.

Configure Eclipse

  1. Go to Preferences | General > Workspace > Linked Resources and create a new resource named GWT_ROOT that points the trunk folder above.
  2. Go to Preferences | Java > Build path > Classpath variables and create a new variable named GWT_TOOLS that points to the tools folder above.

At this point, the gwt-dev and gwt-user projects in your workspace should build without errors. If you’re planning to contribute code to GWT, you’ll also want to import the GWT style formatter for Eclipse.

Run Tests

There are a couple gotchas to running the GWT unit tests in Eclipse. First, some tests seem to require more stack memory than the Eclipse defaults, so you’ll want to add the following parameter under the -vmargs in your eclipse.ini:

-Xss1024k

Second, any tests that extend GWTTestCase, whether directly or up the inheritance chain, must be run as GWT JUnit tests, not regular JUnit tests. Google Plugin for Eclipse automatically makes the “Run as GWT JUnit test” option available in the context menu for GWT projects, but gwt-user itself is not a GWT project. To run a test located in gwt-user as a GWT JUnit test, do the following:

  1. Right-click on the gwt-user project and go to Properties | Google | Web Toolkit. Check the box that says “Use Google Web Toolkit”. The version numbers will be grayed out, but that’s OK. Click OK.
  2. Right-click on the test you’re interested in, say, RequestFactoryJreTest, and select Run As | Run Configurations… In the dialog, click GWT JUnit Test and then the New icon in the upper left corner of the dialog. This will create a new launch config for the test. Click the Run button to run it.

For further reading, here are the detailed instructions on setting up Eclipse to work on GWT source. If you want to contribute a patch to GWT, please see the Making GWT Better page for further instructions.

Happy coding!

Posted in Google Web Toolkit | 3 Comments »

GWT + Maven + GAE gotcha

Posted by David Chandler on March 8, 2011

It turns out that gwt-user-2.2.0, weighing in at 10.6 MB, is just over the App Engine size limit for a single file (10 MB) so you must enable jar splitting to deploy a GWT + Maven project to GAE. Actually, though, there is no need to deploy gwt-user because it’s only used for GWT compilation and GWT dev mode. The GWT Expenses sample POM correctly scopes the gwt-user dependency as “provided” in order to prevent this. However, the sample POM also says in the gwt-maven-plugin config:

<copyWebapp>true</copyWebapp>

This feature of gwt-maven-plugin copies src/main/webapp to the target folder in order for GWT dev mode (gwt:run) to work and inadvertently copies the gwt-user jar, too. Fortunately, if you’re using a POM with copyWebapp=true, you can configure the clean plugin to remove the gwt-user jar from the target folder before GAE deployment:

			<plugin>
				<!-- Don't deploy gwt-user jar to GAE -->
				<artifactId>maven-clean-plugin</artifactId>
				<version>2.3</version>
				<executions>
					<execution>
						<id>default-clean</id>
						<phase>clean</phase>
						<goals>
							<goal>clean</goal>
						</goals>
					</execution>
					<execution>
						<id>remove-gwt-user-jar</id>
						<phase>package</phase>
						<goals>
							<goal>clean</goal>
						</goals>
						<configuration>
							<excludeDefaultDirectories>true</excludeDefaultDirectories>
							<filesets>
								<fileset>
									<directory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</directory>
									<includes>
										<include>gwt-user*jar</include>
									</includes>
								</fileset>
							</filesets>
						</configuration>
					</execution>
				</executions>
			</plugin>

It should be noted that this is only an issue for Maven projects. Google Plugin for Eclipse has long excluded gwt-user.jar from WEB-INF/lib, so standard GPE projects don’t deploy it to App Engine. However, GPE Maven projects allow Maven to manage the classpath, so you’ll need the clean snippet above in your POM to exclude gwt-user from deployment.

A proposed fix is to enhance the gwt-maven-plugin’s copyWebapp feature (which, ironically enough, was contributed by Google) to exclude gwt-user*jar from the copy. Until then, use the clean snippet above or enable jar splitting.

Posted in AppEngine, Google Web Toolkit | 2 Comments »

GWT 2.2 AsyncDataProvider / CellTable gotcha

Posted by David Chandler on March 2, 2011

I’ve been trying out CellTable in GWT 2.2 and found a potential gotcha. I created an AsyncDataProvider and attached the CellTable to it, but found that the table does not refresh properly unless you update BOTH row count and row data. If you call only updateRowData(), the CellTable will show the loading bar when there are zero rows, and will not remove rows when you delete them in the provider. The solution is simple: whenever you want to update a CellTable bound to an AsyncDataProvider, be sure to call both updateRowData() and updateRowCount(). Example code here:

	public static class ListDataProvider extends
			AsyncDataProvider<ItemListProxy>
	{
		private Logger logger = Logger
				.getLogger(ListsActivity.ListDataProvider.class.getName());
		private ListwidgetRequestFactory rf;

		public ListDataProvider(ListwidgetRequestFactory requestFactory)
		{
			this.rf = requestFactory;
		}

		@Override
		protected void onRangeChanged(HasData<ItemListProxy> display)
		{
			getData();
		}
		
		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);
				}
			});
		}
	}

Posted in Google Web Toolkit | 10 Comments »

 
%d bloggers like this: