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.

  • Go to cayenne-tutorial-client project in Eclipse and create a new class called "Main" in cayenne.tutorial.client package.
  • Now open cayenne.tutorial.Main.java file in cayenne-tutorial and copy all contents except for the first line (i.e. skip the package declaration) and paste it to the client main class created above. You will see a bunch of errors in Eclipse. Don't worry about them - we'll address them as we go. Here is how a new Main class may look like in Eclipse:

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.

  • Add the following code in the beginning of the main method, and press "Ctrl-Shift-O" to add missing imports (this would be "Cmd-Shift-O" on Mac OS X):
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.

  • Replace this line
DataContext context = DataContext.createDataContext();

with this

ObjectContext context = new CayenneContext(channel);
  • Now change the signature of all methods that previously accepted DataContext to take ObjectContext instead. Now we are down to just one error. We just replaced concrete class with the interface, but did not change any code. Note that we could've used ObjectContext in the server code as well.

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.

  • Open server cayenne.tutorial.Artist.java class and copy the class contents (everything inside public class Artist extends _Artist {..}). Paste them to the client cayenne.tutorial.client.Artist.java and save the file. The last error in the Main class should now be cleared.

Running the Client

  • Start the server in Eclipse using JettyLauncher.
  • Right click the cayenne.tutorial.client.Main in Eclipse and select "Run As.. > Java Application. You should see a bunch of logs on the client and the server Eclipse consoles showing that the client has connected and executed a number of operations. Specifically the client output may look like this, displaying messages sent to the server:
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