## Starting Command Line Client

One of the benefits of ROP is that the client code is no different from the server code - it uses the same ObjectContext interface for access, same query and commit API. So the code below will be similar to the code presented in the first Cayenne tutorial, although with a few ROP-specific parts required to bootstrap the ObjectContext.

Let's start by creating an empty Main class with the standard main() method in the client project:

    package org.example.cayenne.persistent.client;

    public class Main {

    	public static void main(String[] args) {

    	}
    }

Now the part that is actually different from regular Cayenne - establishing the server connection and obtaining the ObjectContext:

    ClientConnection connection = new HessianConnection("http://localhost:8080/tutorial/cayenne-service");
    DataChannel channel = new ClientChannel(connection);
    ObjectContext context = new CayenneContext(channel);

Note that the "channel" can be used to create as many peer ObjectContexts as needed over the same connection, while ObjectContext is a kind of isolated "persistence session", similar to the server-side context. A few more notes. Since we are using HTTP(S) to communicate with ROP server, there's no need to explicitly close the connection (or channel, or context).

So now let's do the same persistent operaions that we did in the first tutorial "Main" class. Let's start by creating and saving some objects:

    // creating new Artist
    Artist picasso = context.newObject(Artist.class);
    picasso.setName("Pablo Picasso");

    // Creating other objects
    Gallery metropolitan = context.newObject(Gallery.class);
    metropolitan.setName("Metropolitan Museum of Art");

    Painting girl = context.newObject(Painting.class);
    girl.setName("Girl Reading at a Table");

    Painting stein = context.newObject(Painting.class);
    stein.setName("Gertrude Stein");

    // connecting objects together via relationships
    picasso.addToPaintings(girl);
    picasso.addToPaintings(stein);

    girl.setGallery(metropolitan);
    stein.setGallery(metropolitan);

    // saving all the changes above
    context.commitChanges();

Now let's select them back:

    // SelectQuery examples
    SelectQuery select1 = new SelectQuery(Painting.class);
    List<Painting> paintings1 = context.performQuery(select1);

    Expression qualifier2 = ExpressionFactory.likeIgnoreCaseExp(
    		Painting.NAME_PROPERTY, "gi%");
    SelectQuery select2 = new SelectQuery(Painting.class, qualifier2);
    List<Painting> paintings2 = context.performQuery(select2);

Now, delete:

    Expression qualifier = ExpressionFactory.matchExp(Artist.NAME_PROPERTY,
    				"Pablo Picasso");
    SelectQuery selectToDelete = new SelectQuery(Artist.class, qualifier);
    Artist picasso = (Artist) DataObjectUtils.objectForQuery(context,
    		selectToDelete);

    if (picasso != null) {
    	context.deleteObject(picasso);
    	context.commitChanges();
    }

This code is exactly the same as in the first tutorial. So now let's try running the client and see what happens. In Eclipse open main class and select `"Run > Rus As > Java Application"` from the menu (assuming the ROP server started in the previous step is still running). You will some output in both server and client process consoles. Client:

    INFO: Connecting to [http://localhost:8080/tutorial/cayenne-service] - dedicated session.
    INFO: === Connected, session: org.apache.cayenne.remote.RemoteSession@9e09a4[sessionId=10qsakj1mj806] - took 219 ms.
    INFO: --- Message 0: Bootstrap
    INFO: === Message 0: Bootstrap done - took 71 ms.
    INFO: --- Message 1: flush-cascade-sync
    INFO: === Message 1: flush-cascade-sync done - took 1342 ms.
    INFO: --- Message 2: Query
    INFO: === Message 2: Query done - took 58 ms.
    INFO: --- Message 3: Query
    INFO: === Message 3: Query done - took 21 ms.
    INFO: --- Message 4: Query
    INFO: === Message 4: Query done - took 22 ms.
    INFO: --- Message 5: Query
    INFO: === Message 5: Query done - took 16 ms.
    INFO: --- Message 6: Query
    INFO: === Message 6: Query done - took 2 ms.
    INFO: --- Message 7: Query
    INFO: === Message 7: Query done - took 2 ms.
    INFO: --- Message 8: Query
    INFO: === Message 8: Query done - took 2 ms.
    INFO: --- Message 9: flush-cascade-sync
    INFO: === Message 9: flush-cascade-sync done - took 30 ms.

As you see client prints no SQL statmenets, just a bunch of query and flush messages sent to the server. The server side is more verbose, showing the actual client queries executed against the database:

    ...
    INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE [bind: 1:'GALLERY']
    INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE [bind: 1:'ARTIST']
    INFO: SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME = ? FOR UPDATE [bind: 1:'PAINTING']
    INFO: --- will run 3 queries.
    INFO: INSERT INTO GALLERY (ID, NAME) VALUES (?, ?)
    INFO: [batch bind: 1->ID:200, 2->NAME:'Metropolitan Museum of Art']
    INFO: === updated 1 row.
    INFO: INSERT INTO ARTIST (DATE_OF_BIRTH, ID, NAME) VALUES (?, ?, ?)
    INFO: [batch bind: 1->DATE_OF_BIRTH:NULL, 2->ID:200, 3->NAME:'Pablo Picasso']
    INFO: === updated 1 row.
    INFO: INSERT INTO PAINTING (ARTIST_ID, GALLERY_ID, ID, NAME) VALUES (?, ?, ?, ?)
    INFO: [batch bind: 1->ARTIST_ID:200, 2->GALLERY_ID:200, 3->ID:200, 4->NAME:'Girl Reading at a Table']
    INFO: [batch bind: 1->ARTIST_ID:200, 2->GALLERY_ID:200, 3->ID:201, 4->NAME:'Gertrude Stein']
    INFO: === updated 2 rows.
    INFO: +++ transaction committed.
    INFO: --- will run 1 query.
    INFO: --- transaction started.
    INFO: SELECT t0.GALLERY_ID, t0.ARTIST_ID, t0.NAME, t0.ID FROM PAINTING t0
    INFO: === returned 2 rows. - took 15 ms.
    INFO: +++ transaction committed.
    INFO: --- will run 1 query.
    INFO: --- transaction started.
    INFO: SELECT t0.GALLERY_ID, t0.ARTIST_ID, t0.NAME, t0.ID FROM PAINTING t0 WHERE UPPER(t0.NAME) LIKE UPPER(?) [bind: 1->NAME:'gi%']
    INFO: === returned 1 row. - took 9 ms.
    INFO: +++ transaction committed.
    INFO: --- will run 1 query.
    INFO: --- transaction started.
    INFO: SELECT t0.DATE_OF_BIRTH, t0.ID, t0.NAME FROM ARTIST t0 WHERE t0.NAME = ? [bind: 1->NAME:'Pablo Picasso']
    INFO: === returned 1 row. - took 7 ms.
    INFO: +++ transaction committed.
    INFO: --- will run 2 queries.
    INFO: --- transaction started.
    INFO: DELETE FROM PAINTING WHERE ID = ?
    INFO: [batch bind: 1->ID:200]
    INFO: [batch bind: 1->ID:201]
    INFO: === updated 2 rows.
    INFO: DELETE FROM ARTIST WHERE ID = ?
    INFO: [batch bind: 1->ID:200]
    INFO: === updated 1 row.
    INFO: +++ transaction committed.

You are done with the basic ROP client!

Next Step: Remote Object Persistence Tutorial Authentication