Skip to content

Implementing Paging on Google App Engine Java (gae/j) and GWT — the query cursor way

by dkberktas on August 12th, 2010

For the etohum admin application application, we used Goole App Engine Java (gae/j) two years ago, back then, the way to implement paging was not that easy. Because of that we came up with our custom way and implemented a combination of memcached+servlet+cron jobs update mechanism which introduced many bugs and took many hours to reach perfection.

Since Burak hoca asks for an enhancements recently, we go through the app engine documentation and see this new feature query cursors which is excellent for paging.

The idea behind query cursors is pretty simple, make a query for the first page, pass the cursor data to the client. When you need the second page,  instead of  making a query from scracth, use the cursor data to get the next page’s data.

In our case the RPC call  getApplications(String cursor) is called. For the first page, cursor data is passed as null, so we make the query as follows:

if (cursorString == null)
{
	//
	Query query = pm.newQuery(Application.class);
	query.setOrdering("basvuruTarihi desc");
	query.setRange(0, 15);

	results = (List) query.execute();

	Cursor cursor = JDOCursorHelper.getCursor(results);
	resultWrapper.setCursorData(cursor.toWebSafeString());

	for (Iterator iterator = results.iterator(); iterator.hasNext();)
	{
		Application applicationFromDatabase = (Application) iterator.next();
		app = DunyaTurkOlsunUtil.createApplicationDTO(applicationFromDatabase);
		resultAppList.add(app);
	}
	resultWrapper.setResultAppList(resultAppList);
}

So this code above fetch the first page and cursor string. On the client side, inside GWT, we hold the cursor string for each page in an arraylist, so that we can handle going back and forth between the pages.

When the user asks for the second pages, the following code block executes

else
{
	Cursor cursor = Cursor.fromWebSafeString(cursorString);
	Map extensionMap = new HashMap();
	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
	Query query = pm.newQuery(Application.class);
	query.setOrdering("basvuruTarihi desc");

	query.setExtensions(extensionMap);
	query.setRange(0, 15);

	results = (List) query.execute();
	resultWrapper.setCursorData(JDOCursorHelper.getCursor(results).toWebSafeString());

	for (Iterator iterator = results.iterator(); iterator.hasNext();)
	{
		Application applicationFromDatabase = (Application) iterator.next();
		app = DunyaTurkOlsunUtil.createApplicationDTO(applicationFromDatabase);
		//
		resultAppList.add(app);
	}
	resultWrapper.setResultAppList(resultAppList);
}

//
This works even faster than memcached version of ours. 

ps. By the way, there is still no way of passing JDO objects through RPC calls which is sad for GWT apps on GAE/J/

From → gwt, tech

2 Comments
  1. Annonymous permalink

    thanks for this good post, was extremely helpful to me

Trackbacks & Pingbacks

  1. GAE Query Filter, Sort, Limit, Paging | ?????????

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS