Skip to content
This repository has been archived by the owner on Jun 26, 2024. It is now read-only.
chrislewis edited this page May 24, 2011 · 9 revisions

Highchair remote is a wrapper for Google App Engine's Remote API, allowing any Java application to transparently access App Engine services. You could use it to write raw Entitys to a remote application just as easily as you could write highchair entities. Note that remotes allow you interface with any GAE service supported by the Remote API, not just the data store.

Dependencies

The remote module wraps the Remote API, which is provided by the GAE sdk in the jar appengine-remote-api.jar. This is its only dependency, and unfortunately it's not published in the maven repositories. This can cause surprising failures, but sbt at least makes it easy to manage such dependencies (see manual dependency management). Even though it's easily worked around, it is an unnecessary hurdle. I've opened an issue; please go vote it up.

Application Configuration

In order to use the Remote API, the application must be configured to support remote calls. This requires wiring a GAE-provided servlet in your web.xml. Details here.

Initializing a Remote

A Remote instance must be initialized against an application for which you have an administrative account. You provide the application id and port as a tuple, and an administrative account with its password as another tuple:

val remote = Remote("localhost" -> 8080, "[email protected]" -> "foopass")

This example would run against a local development server. However, the remote module contains a pre-configured instance for an application on localhost:8080 (the default): Remote.local.

See the Remote API documentation for full details.

Executing Remote Operations

Persisting a Remote Highchair Entity

Assuming Person is a defined highchair entity, instances can be persisted to a remote data store using a remote block:

val me = Person(None, "Chris", "Aaron", "Lewis", 30)
implicit val ds = DatastoreServiceFactory.getDatastoreService

remote {
  Person.put(me)
}

Note that neither the me or ds instances needed to be created within the remote block.

Handling Results

Calls to remote result in an Either[Throwable, A], where A is the result type of the block. This allows you to sanely retrieve results, if you want them on success, as well as deal with any failures. Continuing with the Person example, suppose we have the following functions for generating an error or welcome view fragment, respectively:

val errorReponse = (e: Throwable) => <h3>Please Try Again Later!</h3>
val welcomeResponse = (p: Person) => <h3>Welcome {p.firstName}!</h3>

This makes it easy to fold a remote result into a view fragment:

remote {
  Person.put(me)
} fold (errorReponse, welcomeResponse)

Scoping

Remotes allow you to scope remote calls such that when the block terminates, subsequent service calls will resume local bindings. This is achieved through the loan pattern. Therefore, you don't need to worry about remote calls wreaking havoc, even if they fail; cleanup happens automatically in all scenarios.