Chapter 2. Development and deployment with Rio
Prev | Part I. Getting Started Guide | Next

## Chapter 2. Development and deployment with Rio

## Development with Jini Service Beans (JSB)

In this part of the Getting Started Guide, we will rewrite the same service as in the previous section, but using Rio facilities this time. This will illustrate how Rio simplifies coding of Jini services and what facilities it adds.

### The service

The contract of our service remains the same. There is no need for modification of the `Echo` interface.

### The service proxy

The proxy we developed in Chapter 1 was not a really good Jini citizen. For example it was not keeping track of its service ID and was not administrable (you could not change the attributes of the service, you could not ask it to register to another lookup service, etc.).

By default Rio turn our services into good Jini citizen. In order to ease most of the required work, Rio provides an abstract class which should be used for most of our Rio services: `AbstractProxy`. Here is the modified service proxy using Rio:

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

        public EchoProxy(RemoteEcho backend, Uuid uuid) {
            super(backend, uuid);
            this.backend = backend;
        }

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

### The remote service

In the previous chapter we created an `EchoService` class whose responsibility was to register our smart proxy with the lookup service. This time, however, Rio will do it for us. All we'll have to do is to give our proxy to Rio.

### Note

If you want to customize things a bit more (like using a different `Exporter` than the default one), you will still be able to do it.

The easiest way to write a Jini Service Bean is to create a subclass of `ServiceBeanAdapter`. In this example, we will override the `initialize()` method in order to build our own delegate to perform the business logic. Here is the code of the JSB:

    public class EchoJSB extends ServiceBeanAdapter implements RemoteEcho {
        private RemoteEcho delegate;

        public void initialize(ServiceBeanContext context) throws Exception {
            super.initialize(context);
            delegate = new RemoteEchoImpl();
        }

        protected Object createProxy() {
            return new EchoProxy((RemoteEcho) getExportedProxy(), getUuid());
        }

        public String echo(String message) throws RemoteException {
            String result = delegate.echo(message);
            return result;
        }
    }

### Note

In the above example we can see that we overwrite the `createProxy()` method. If we were not using a smart proxy (meaning our proxy would simply be a stub for our remote service), this would have been an unnecessary step.

Rio provides powerful SLA (Service Level Agreement) support. In our JSB we can add watches which the SLA section of our opstring can reference. In this example we are going to add watches monitoring the number of calls made to our service (more precisely to an instance of our service), the meantime of a call, and the number of calls per second. This is trivial to do, and the source code should be sufficient in order to understand how this works:

    public class EchoJSB extends ServiceBeanAdapter implements RemoteEcho {
        private RemoteEcho delegate;
        private CounterWatch rate;
        private ThroughputWatch throughtput;
        private StopWatch meanTime;

        public void initialize(ServiceBeanContext context) throws Exception {
            super.initialize(context);
            delegate = new RemoteEchoImpl();
            rate = new CounterWatch("rate");
            throughtput = new ThroughputWatch("throughtput");
            meanTime = new StopWatch("meanTime");
            context.getWatchRegistry().register(rate);
            context.getWatchRegistry().register(throughtput);
            context.getWatchRegistry().register(meanTime);
        }

        protected Object createProxy() {
            return new EchoProxy((RemoteEcho) getExportedProxy(), getUuid());
        }

        public String echo(String message) throws RemoteException {
            meanTime.startTiming();
            String result = delegate.echo(message);
            meanTime.stopTiming();
            rate.increment();
            throughtput.increment();
            return result;
        }

        public class ThroughputWatch extends PeriodicWatch {
            private int numberOfCalls = 0;

            public ThroughputWatch(String id) {
                super(id);
                super.setPeriod(1 * 1000);
            }

            public void checkValue() {
                super.addWatchRecord(new Calculable("taux", numberOfCalls / (getPeriod() / 1000)));
                numberOfCalls = 0;
            }

            public void increment() {
                numberOfCalls++;
            }
        }
    }

### Running the service

As before, make sure your Rio infrastructure is running with the command: rio start all.

Before we run our service, we need to create two JARs: one for our service implementation, and one for the downloadable code (like the classes linked to the proxy which are "downloaded" in the client JVM). All this work is done by running ant deploy which will package those JARs and deploy them into the <RIO_HOME>/deploy directory so that the JARs can be available from Rio web server (called Webster).

After running ant deploy, we will have the following output in the Rio console:

    Dec 19, 2006 5:11:52 PM org.jini.rio.monitor.ProvisionMonitorImpl deploy
    FINE: Deploying Operational String [Echo]
    Dec 19, 2006 5:11:52 PM org.jini.rio.monitor.ServiceElementManager verify
    FINE: ServiceElementManager.verify(): [Echo] actual [0], pending [0], maintain [1]
    Dec 19, 2006 5:11:52 PM org.jini.rio.monitor.ServiceResourceSelector selectServiceResource
    FINER: Cybernode at [192.168.1.100] has [0] instance(s), planned [1] of [Echo]
    Dec 19, 2006 5:11:52 PM org.jini.rio.monitor.InstantiatorResource meetsQuantitativeRequirements
    FINER: Evaluate [2] System Threshold Requirements for [Echo] using Cybernode at [192.168.1.100]
    [CPU] utilization requirement met. Desired Low=[0.0], High=[0.999], Actual=[0.0]
    [System] utilization requirement met. Desired [0.999], Actual [0.35184708448257423]
    Dec 19, 2006 5:11:52 PM org.jini.rio.monitor.InstantiatorResource canProvision
    FINER: Cybernode at [192.168.1.100] meets qualitative requirements for [Echo]
    Dec 19, 2006 5:11:52 PM org.jini.rio.monitor.ServiceProvisioner$ProvisionTask doProvision
    FINER: Allocating [Echo] ...
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.JSBLoader create
    FINEST: Load service class: class tutorial.EchoJSB
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.JSBLoader create
    FINEST: Activating as ServiceBean
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.JSBLoader create
    FINEST: Obtained implementation constructor: public tutorial.EchoJSB()
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanAdapter <init>
    FINEST: Set configuration component name as : tutorial
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.JSBLoader create
    FINEST: Obtained implementation instance: tutorial.EchoJSB@82e581
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanAdapter initialize
    FINE: Create ServiceID from UUID b520bd7d-603d-48b4-8fff-2c8a4514e3fd
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanSLAManager createSLAPolicyHandler
    FINEST: [Echo] SLA [rate] Created SLAPolicyHandler [org.jini.rio.qos.ScalingPolicyHandler]
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanSLAManager addSLAs
    FINEST: [Echo] Adding SLA [rate] to the Watch Registry for subsequent association
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanSLAManager createSLAPolicyHandler
    FINEST: [Echo] SLA [throughtput] Created SLAPolicyHandler [org.jini.rio.qos.SLAPolicyHandler]
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanSLAManager addSLAs
    FINEST: [Echo] Adding SLA [throughtput] to the Watch Registry for subsequent association
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanAdapter advertise
    FINEST: [Echo] ServiceBeanAdapter.advertise()
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanAdapter advertise
    FINEST: [Echo] verify transition
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanAdapter advertise
    FINEST: [Echo] do the join
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.JSBContext getDiscoveryManagement
    FINEST: Create DiscoveryManagement for Echo
    Dec 19, 2006 5:11:53 PM org.jini.rio.jsb.ServiceBeanAdapter advertise
    FINEST: [Echo] set state to ADVERTISED
    Dec 19, 2006 5:11:53 PM org.jini.rio.cybernode.JSBDelegate advertise
    FINE: Echo: advertised
    Dec 19, 2006 5:11:53 PM org.jini.rio.monitor.ServiceProvisioner$ProvisionTask doProvision
    FINER: Allocated [Echo]
    Dec 19, 2006 5:11:53 PM org.jini.rio.monitor.ServiceElementManager$JSBProvisionListener serviceProvisioned
    FINE: [Echo] service provisioned, instance=Instance=[1] Proxy=[tutorial.EchoProxy] ID=[b520bd7d-603d-48b4-8fff-2c8a4514e3fd] HostAddress=[192.168.1.100]
    Dec 19, 2006 5:11:53 PM org.jini.rio.monitor.ServiceElementManager instanceIDLog
    FINE: [Echo] Added SBI = 1, b520bd7d-603d-48b4-8fff-2c8a4514e3fd
         Instance ID list [1]
         ServiceBeanInstance List:
         Instance=[1] Proxy=[tutorial.EchoProxy] ID=[b520bd7d-603d-48b4-8fff-2c8a4514e3fd] HostAddress=[192.168.1.100]

### Running the client

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

    Buildfile: build.xml
         [echo] jini.lib : /Users/jeje/Documents/Development/experimental/rio/rio/examples/tutorial/rio-example/../../../lib/jini2_1/lib
         [echo] rio.lib  : /Users/jeje/Documents/Development/experimental/rio/rio/examples/tutorial/rio-example/../../../lib

    client:
         [java] May 18, 2007 9:55:52 AM tutorial.EchoClient <init>
         [java] INFO: Searching for echo service
         [java] May 18, 2007 9:55:52 AM tutorial.EchoClient discovered
         [java] INFO: Discovered registrar f9507493-aceb-40b1-99d6-ee6338e49a88
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class $Proxy2
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class org.jini.rio.cybernode.CybernodeProxy$ConstrainableCybernodeProxy
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class tutorial.EchoProxy
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class org.jini.rio.monitor.ProvisionMonitorProxy$ConstrainableProvisionMonitorProxy
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient discovered
         [java] INFO: Found proxy of class class com.sun.jini.reggie.ConstrainableRegistrarProxy
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient <init>
         [java] INFO: Found service with ID 3cd3f0de-99ba-4309-a683-43b726d1ed26
         [java] May 18, 2007 9:55:53 AM tutorial.EchoProxy echo
         [java] INFO: In proxy!!!
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient <init>
         [java] INFO: Echo of hello (0) is: hello 0
         [java] May 18, 2007 9:55:53 AM tutorial.EchoProxy echo
         [java] INFO: In proxy!!!
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient <init>
         [java] INFO: Echo of hello (1) is: hello 1

         ...

         [java] May 18, 2007 9:55:53 AM tutorial.EchoProxy echo
         [java] INFO: In proxy!!!
         [java] May 18, 2007 9:55:53 AM tutorial.EchoClient <init>
         [java] INFO: Echo of hello (9) is: hello 9

    BUILD SUCCESSFUL
    Total time: 2 seconds

### Understanding Rio OpStrings

In order to deploy our service, we asked Rio to deploy our OpString. An opstring is a file that describes how Rio should deploy our service, what it's dependencies are, and additional requirements of our service.

An OpString can define many services (or Jini Service Beans) for deployment. For each service we need to identify the interface of our Jini service (our business contract and the interface our proxy needs to implement) and the name of our JSB class and their respective JARs and dependencies. Here is a minimal JSB configuration:

    <ServiceBean Name="Echo">
      <Interfaces>
        <Interface>tutorial.Echo</Interface>
        <Resources>
          <JAR>rio-example/lib/rio-example-dl.jar</JAR>
        </Resources>
      </Interfaces>

      <ImplementationClass>tutorial.EchoJSB
        <Resources>
          <JAR>rio-example/lib/rio-example.jar</JAR>
        </Resources>
      </ImplementationClass>
    </ServiceBean>

But sometimes we need more than one instance of our service running (perhaps because we need fail-over or load balancing). Rio can take care of this and ensure that at least a specified number of services are running and spread in the cluster. Suppose we'd like to have 5 instances of our service running with a maximum of 3 instances per cybernode. Here is how we would define our OpString:

    <ServiceBean Name="Echo">
      <Interfaces>
        <Interface>tutorial.Echo</Interface>
        <Resources>
          <JAR>rio-example/lib/rio-example-dl.jar</JAR>
        </Resources>
      </Interfaces>

      <ImplementationClass>tutorial.EchoJSB
        <Resources>
          <JAR>rio-example/lib/rio-example.jar</JAR>
        </Resources>
      </ImplementationClass>

      <Maintain>5</Maintain>
      <MaxPerMachine>3</MaxPerMachine>
    </ServiceBean>

### Understanding Rio SLAs

Start the Rio Monitor. We should have two instances of our service running. Right-click on the one on our left.

Then right click on a service instance (one of the geen circles), then select "Show Service UI". If we click on the `meanTime` watch, we'll have an output like this one:

On this screenshot we can see how long it took to process each request.

If we look carefully at the `rio-example.xml` file which is available in `rio-example/resources` (the one we asked Rio to deploy), we'll see the following lines:

    <ServiceLevelAgreements>
      <SLA ID="rate" Low="0" High="5">
        <PolicyHandler type="scaling" max="5" lowerDampener="10000" upperDampener="200"/>
      </SLA>
      <SLA ID="throughtput" High="2">
        <PolicyHandler type="notify"/>
      </SLA>
      <SystemRequirements>
        <Utilization ID="System" High=".999"/>
        <Utilization ID="CPU" High=".999"/>
      </SystemRequirements>
    </ServiceLevelAgreements>

This configuration defines two SLAs: one on the `rate` watch, and another one on the `throughput` watch. For the `throughput` watch, we ask Rio to notify us when the throughput is higher than 2 (calls per second). For the `rate` watch, we ask Rio to scale the number of instances running (one at the beginning) up to 5 if we have more than 5 calls (the client is doing 10 calls on the service). We can usually see the low and high marks on the administrative UI, as we can see in the following screenshot:

This explains why after running the client, we end up with two instances of our service.

Prev | Up | Next
Deployment of Jini services | Home | Development with POJOs