Title: Remote Object Persistence Tutorial Client Code

Starting Command Line Client

One of the benefits of Cayenne remote object persistence technology is that the client persistence code uses the same API as the server code. We will demonstrate this by porting the command-line Cayenne application developed as a part of Quick Start tutorial to a remote client.

Client Migration Strategy

An explanation of the migration strategy is due before we go further. For simplicity we will call (somewhat inaccurately) the original tutorial code "server code" and the resulting remote client - "client code". There are the following differences between the server and the client persistence code:

  1. Attaching to the Cayenne stack is done differently.
  2. Server code uses DataContext, while client uses CayenneContext
  3. Server and client are using different sets of persistent classes.

We will discuss these differences in detail below. Here we will just note that the first two items do not significantly affect the code portability (by "portability" we mean the ability to reuse the same persistence code on the client and on the server). The trick is to use interfaces common to the server and the client, but provide different implementations. However the last issue (already mentioned earlier) complicates code reuse and portability. Still it is certainly not a show-stopper.

Building the Stack

Traditionally Cayenne initializes the shared stack (everything below the DataContext) using the information from cayenne.xml descriptor. On the client there are no descriptors present, so a simple API call is normally used.

Main.java
		ClientConnection connection = new HessianConnection("http://localhost:8080/cayenne-service");
DataChannel channel = new ClientChannel(connection);

This is all you need to connect to the remote service. Note that DataChannel abstraction is used on the server as well, it is just not as visible - DataDomain implements DataChannel.

XyzContext

There is no DataContext on the client (hence Eclipse errors highlighting the attempts to use it). So let's convert the code to a portable code that would work on both client and server the same way. This is done by using ObjectContext interface that is implemented by DataContext and also by CayenneContext that we should be using on the client.

DataContext context = DataContext.createDataContext();

with this

ObjectContext context = new CayenneContext(channel);

Reconcile business logic

The only remaining error is caused by this line:

picasso.setDateOfBirthString("18811025");

As was mentioned earlier, this piece needs improvement in Cayenne. As of release 1.2 the client and the server classes, while sharing all properties, do not share the business logic. So it has to be copy/paste, and this is what we are going to do.

Running the Client

ul 4, 2006 2:18:23 PM org.objectstyle.cayenne.remote.hessian.HessianConnection connect
INFO: Connecting to [http://localhost:8080/cayenne-service] - dedicated session.
Jul 4, 2006 2:18:24 PM org.objectstyle.cayenne.remote.hessian.HessianConnection connect
INFO: === Connected, session: org.objectstyle.cayenne.remote.RemoteSession@7918f0[sessionId=k2h7fmgw8ecd] - took 672 ms.
Jul 4, 2006 2:18:24 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 0: Bootstrap
Jul 4, 2006 2:18:24 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 0: Bootstrap done - took 235 ms.
Jul 4, 2006 2:18:24 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 1: Query
Jul 4, 2006 2:18:27 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 1: Query done - took 2588 ms.
Jul 4, 2006 2:18:27 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 2: flush-cascade-sync
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 2: flush-cascade-sync done - took 608 ms.
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 3: Query
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 3: Query done - took 220 ms.
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 4: Query
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 4: Query done - took 40 ms.
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 5: Query
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 5: Query done - took 94 ms.
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 6: Query
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 6: Query done - took 81 ms.
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: --- Message 7: flush-cascade-sync
Jul 4, 2006 2:18:28 PM org.objectstyle.cayenne.remote.BaseConnection sendMessage
INFO: === Message 7: flush-cascade-sync done - took 155 ms.

You are done with a basic client!


Next Step: Remote Object Persistence Tutorial Authentication