Deployment of Jini services
Prev | Chapter 1. Development with Jini and deployment with Rio | Next

## Deployment of Jini services

### The service

Our first Jini service is going to be a simple Echo service. The contract for this service is going to be quite simple:

    public interface Echo {
        String echo(String message) throws RemoteException;
    }

Notice that the method in the interface is declared to throw a `java.rmi.RemoteException`. Although this exception is in the RMI package, this does not mean our service will use RMI (in fact in won't).

### Warning

Do not forget that all the methods of the proxy must throw `java.rmi.RemoteException`s! This is anyway a good practice for your Jini services as you should not try to hide the network.

The source code for this example in the <RIO_HOME>/examples/tutorial/jini-example directory.

### The service proxy

The client code used to call our service is a proxy. Jini provides a capability that allows proxies to optionally contain methods that run locally on the client and do not perform a remote method call to the proxy's corresponding service. In fact, it's possible to write a proxy that makes no remote calls at all. A proxy containing locally-run code is called a smart proxy. For this example, our Jini smart proxy is going to both log output on the client and call the service backend in order to remotely run the `echo()` method. The proxy will extend our `Echo` interface, introduced above, using the following interface:

    public interface RemoteEcho extends Echo, Remote, Serializable {
    }

### Note

Why are we using two interfaces instead of modifying the first one so that it extends `Remote`? This is because our proxy is not a `Remote` object. It is a client of a RemoteEcho service being our Jini server (the part running remotely). When the contract of a remote service is the same as the one of the proxy, simply create an interface for the remote service which extends the one of the proxy and extends the `java.rmi.Remote` interface. That way the contract of our Jini service can stay the same even if we don't have a remote service (which is the case when all the code is running in the client JVM).

As explained above, the service proxy will simply log that it is calling the backend and call the remote service.

    public class EchoProxy implements Echo, Serializable {
        private RemoteEcho backend;
        private static final Logger logger = Logger.getLogger(EchoProxy.class.getName());

        public EchoProxy(RemoteEcho backend) {
            this.backend = backend;
        }

        public String echo(String message) throws RemoteException {
            logger.info("In proxy!!!");
            return backend.echo(message);
        }
    }

This proxy is built with a reference to the remote service it is going to talk to in order to execute the business logic of the `echo()` method.

### The remote service

Our business logic is going to be separated from the service itself so that we can write the business logic as a simple POJO. Our service backend will simply delegate its work to this POJO.

    public class RemoteEchoImpl implements RemoteEcho {
        private static final Logger logger = Logger.getLogger(RemoteEchoImpl.class.getName());

        public String echo(String message) throws RemoteException {
            logger.info("Echoing " + message);
            return message;
        }
    }

Our service backend is going to discover the Jini Lookup Service, then register the proxy and finally wait for clients to come up. Most of the logic of the service is coded in the constructor of the `EchoService` class.

First we make sure there is a security manager set up, otherwise we'll use the one RMI provides:

    if (System.getSecurityManager() == null)
        System.setSecurityManager(new RMISecurityManager());

Next, we build our backend, instantiate a `LookupDiscoveryManager` for discovery of the lookup service and instantiate a `LeaseRenewalManager` in order to be able to renew the service registration lease.

    RemoteEcho backend = new RemoteEchoImpl();
    LeaseRenewalManager lrm = new LeaseRenewalManager();
    LookupDiscoveryManager discoveryManager = new LookupDiscoveryManager(new String[]{"rio"}, null, this);

### Note

The above "rio" string identifies the name of the group we are going to use when registering and discovering our services. The ability to partition your services is especially needed when you have many computers running on your network, but you'd like to create separate environment, such as a staging one and an integration testing one.

Now we need to build our proxy. Our proxy will need a reference to a remote service. When using JERI, Jini's powerful RMI implementation, we can use a `net.jini.export.Exporter` instance to export our service on the network. The `Exporter` takes our service instance and creates a proxy that implements our service's interface but manages all the network communication on behalf of our client. Once our remote backend is exported, we can give our smart proxy a reference to it. In order to make the `Exporter` user configurable, it is built from a Jini configuration file.

    Configuration config = ConfigurationProvider.getInstance(new String[] {"resources/example1.config"});
    Exporter exporter = (Exporter) config.getEntry( "EchoService", "exporter", Exporter.class);
    Object proxy = new EchoProxy((RemoteEcho) exporter.export(backend));

Having created our service proxy, we need to register the proxy in the lookup service. In order to register our service with the Jini lookup service, we need to create a unique ID which will be used as a way to make sure we are talking to the same service later on. This is done by building a UUID (Universal Unique ID) which is used in order to build a `ServiceID`. Now most of the work is going to be done by the `JoinManager` utility class. The utility class is given the proxy to register in the lookup service, the attributes of our service (in this case a name), the ID of the service and some few other parameters.

    Uuid uuid = UuidFactory.generate();
    ServiceID serviceID = new ServiceID(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits());

    JoinManager joinManager = new JoinManager(
                    proxy,
                    new Entry[] {
                            new Name("Echo Service")
                    },
                    serviceID,
                    discoveryManager,
                    lrm,
                    config
    );

### Running the service

So far our service is a plain old Jini service and does not require nor take advantage of Rio. The service could be run via Jini, for instance using the Jini Starter Kit (Sun's open-source implementation of the Jini specs), however since this is a Rio tutorial and Rio is capable of running raw Jini services, we will be using it to run this example. In order to start Rio, simply run the following command: rio start all in your `<RIO_HOME>/bin` directory.

Next, edit the `build.xml` file in the `<RIO_HOME>/examples/tutorial/jini-example` directory. If you scroll down in the file, near the end you will find twice the text `YOUR_IP_ADDRESS`. Replace those texts with the real IP address (or hostname) of your computer.

### Warning

Do not forget this step!

In order to run our service, simply run ant deploy. This will build the various JARs (such as the implementation of the service, the downloadable code, etc.) and copy those artifacts in the proper directory so that Rio can serve them to our client. We should end up with the following output in your console:

    Buildfile: build.xml

    run:
         [java] Dec 18, 2006 7:14:09 PM tutorial.EchoService <init>
         [java] INFO: Registering service proxy
         [java] Dec 18, 2006 7:14:10 PM tutorial.EchoService discovered
         [java] INFO: Discovered registrar 8cdd9aa8-4f32-4c46-b38f-bbf5070db43c
         [java] Dec 18, 2006 7:14:10 PM tutorial.EchoService <init>
         [java] INFO: Service has registered and is ready...
         [java] Dec 18, 2006 7:14:10 PM tutorial.EchoService discovered
         [java] INFO: Found proxy of class class com.sun.jini.reggie.ConstrainableRegistrarProxy
         [java] Dec 18, 2006 7:14:10 PM tutorial.EchoService discovered
         [java] INFO: Found proxy of class class org.jini.rio.cybernode.CybernodeProxy$ConstrainableCybernodeProxy
         [java] Dec 18, 2006 7:14:10 PM tutorial.EchoService discovered
         [java] INFO: Found proxy of class class $Proxy2
         [java] Dec 18, 2006 7:14:10 PM tutorial.EchoService discovered
         [java] INFO: Found proxy of class class org.jini.rio.monitor.ProvisionMonitorProxy$ConstrainableProvisionMonitorProxy

We should see our service running with the Rio Monitor (run <RIO_HOME>/bin/rio):

### Running the client

Our client is going to call our remote service through our proxy. We will request our service to echo 9 times the string "hello" followed by the index of the current iteration.

An Ant target is provided in order to easily start our Jini client. We simply need to run ant client in order to run it:

    Buildfile: build.xml

    run-client:
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient <init>
         [java] INFO: Searching for echo service
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient discovered
         [java] INFO: Discovered registrar 8cdd9aa8-4f32-4c46-b38f-bbf5070db43c
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class com.sun.jini.reggie.ConstrainableRegistrarProxy
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class org.jini.rio.tutorial.EchoProxy
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class org.jini.rio.cybernode.CybernodeProxy$ConstrainableCybernodeProxy
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class $Proxy2
         [java] Dec 18, 2006 7:25:33 PM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class org.jini.rio.monitor.ProvisionMonitorProxy$ConstrainableProvisionMonitorProxy
         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoClient <init>
         [java] INFO: Found service with ID 071330e8-fb8a-4256-a9a5-1db188f96691
         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoProxy echo
         [java] INFO: In proxy!!!
         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoClient <init>
         [java] INFO: Echo of hello (0) is: hello 0
         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoProxy echo
         [java] INFO: In proxy!!!
         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoClient <init>
         [java] INFO: Echo of hello (1) is: hello 1

         .
         .
         .

         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoProxy echo
         [java] INFO: In proxy!!!
         [java] Dec 18, 2006 7:25:34 PM tutorial.EchoClient <init>
         [java] INFO: Echo of hello (9) is: hello 9

    BUILD SUCCESSFUL
    Total time: 2 seconds

As we can see in the console, our proxy dumped log statements (`EchoProxy` logger used) as expected by the use of a smart proxy (remember that our smart proxy, running in the client JVM log calls and invoke the remote service having the real business logic). Our client was able to talk with the server. Meanwhile the server had the following logs on its console:

         [java] Dec 18, 2006 7:25:34 PM tutorial.RemoteEchoImpl echo
         [java] INFO: Echoing hello 0
         [java] Dec 18, 2006 7:25:34 PM tutorial.RemoteEchoImpl echo
         [java] INFO: Echoing hello 1

         .
         .
         .

         [java] Dec 18, 2006 7:25:34 PM tutorial.RemoteEchoImpl echo
         [java] INFO: Echoing hello 9

Prev | Up | Next
Chapter 1. Development with Jini and deployment with Rio | Home | Chapter 2. Development and deployment with Rio