ENTERPRISE JAVAHow to Use Jini Distributed Leasing

How to Use Jini Distributed Leasing

Kathy Kozel

Listing 6. The remote Jini service, which grants leases.

import java.rmi.server.*;
import java.rmi.*;
import net.jini.core.lease.*;

// this class acts like a landlord as well as being the service provider
// so when you get a lease, you actually call back to this kennel 
// (the lease makes remote calls back to the kennel)

public class KennelImpl extends UnicastRemoteObject implements
 Kennel {

      protected int totalRooms = 10; // the number of rooms I have
      protected TrainerRoom[] kennelRooms = 
      new TrainerRoom[totalRooms];
      protected static final int MAX_LEASE = 1000 * 60 * 1; // a "lease policy"

      public Confirmation bookRoom(Trainable aTrainable,
      long requestedDuration) throws RemoteException {

             System.out.println("attempting to find a room");
             int roomNum = findAvailableRoom();
             if (roomNum >= 0) {
               // there's a room available, so do the work required
               // to grant a Lease and return a Confirmation to client

               long grantedDuration = 
               String ID = String.valueOf(aTrainable.hashCode());

               // create the new Confirmation (which creates the new
               // lease)
               Confirmation confirm = new Confirmation(this, 
               grantedDuration, ID, roomNum);

               // put the Trainable into the room, and give the room
               // enough info to use for leasing (Kennel will ask the
               // room for this info when verifying the lease)


               return confirm;
         else {
           throw new RemoteException("no room", 
           new LeaseDeniedException("No rooms available"));

      protected long determineExpiration(long requested) {
            // This method must enforce the lease duration policy.
            // There could be elaborate more code here, or a call to
            // another object whose sole job is to determine lease
            // expirations.

            if (requested > MAX_LEASE || requested == Lease.ANY)
                return MAX_LEASE;
               return requested;

      protected int findAvailableRoom() {
         for(int i = 0; i < kennelRooms.length; i++) {
           if (kennelRooms[i].getTrainable() == null) {
             return i;
         return -1; // no rooms available

    public long extendStay(String theID, int theRoomNum,
     long requestedDuration) throws RemoteException {
        if (verifyLease(theID, theRoomNum))
          long grantedDuration = determineExpiration(
          return grantedDuration;

          throw new RemoteException("unable to renew");


    public KennelImpl() throws RemoteException {
        for (int i = 0; i < kennelRooms.length; i++) {
          kennelRooms[i] = new TrainerRoom();

   public void cancelStay(String theID, int theRoomNum) throws
    RemoteException {
       if (verifyLease(theID, theRoomNum)) {
         System.out.println("canceling lease");


   protected void freeUpRoom(int theRoomNum) {
      // there's really no need to bother with expiration
      // since when a new Dog is added a new expiration will be set

   public Trainable takeTrainableHome(String theID, int
    theRoomNum) throws RemoteException {
      if (verifyLease(theID, theRoomNum)) {
         System.out.println("About to return dog back to client");
         Trainable t = kennelRooms[theRoomNum].getTrainable();
         return t;
     else {
       throw new RemoteException("Unable to return your dog");
private boolean verifyLease(String theID, int theRoomNum) throws
RemoteException {
      if (theRoomNum >= kennelRooms.length) {
        return false;  // not a valid room index

       TrainerRoom room = kennelRooms[theRoomNum];

       if (room.getTrainable() == null) {
         System.out.println("there's no dog here!");
         throw new RemoteException("", new 
          UnknownLeaseException("No dog in this room!"));

       if ( !(room.getID().equals(theID))) {
         throw new RemoteException("invalid ID for this room", new
          UnknownLeaseException("You do not have this lease"));

       // if we got here, then we're just looking for lease time
      if (room.getExpiration() < System.currentTimeMillis()) {
        System.out.println("this room has expired! We're taking dog
         out now!");
        // we must set this kennel room's trainable to null
        throw new RemoteException("lease expired", new

      return true; //if we made it here, we're good to go!

   // an inner class to do the thread renewal
   class LeaseExpirationChecker implements Runnable {
      public void run() {
         // NOT implemented, but if required, it would
         // simply wake up periodically and walk through the
         // TrainerRoom array to search for expired leases
         // (and boot out any offenders)
         // In a "real" Kennel implementation, the TrainerRoom would
         // be consuming cycles for each Trainable it was training
         // so we would probably want to implement this method
         // NOTE: The TrainerRoom itself is NOT responsible for
         // tracking expired leases. It just trains Trainables as
         // long as they are in a Room, regardless of the Lease.

   public static void main (String args[]) {
     try {
        Kennel theKennelService = new KennelImpl();
        System.out.println("successfully instantiated the
         KennelImpl... about to bind");
        Naming.rebind("Kennel", theKennelService);
        System.out.println("Kennel was successfully bound");
      catch(Exception e) {
        System.out.println("Problem binding service");