ENTERPRISE JAVAHow to Use Jini Distributed Leasing

ENTERPRISE JAVA
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 = 
               determineExpiration(requestedDuration);
               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)

               kennelRooms[roomNum].setTrainable(aTrainable);
               kennelRooms[roomNum].setExpiration(grantedDuration);
               kennelRooms[roomNum].setID(ID);

               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;
              }
             else
              {
               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(
           requestedDuration);
          kennelRooms[theRoomNum].setExpiration(grantedDuration);
          return grantedDuration;
         }
        else
         {

          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");
         freeUpRoom(theRoomNum);
        }

    }

   protected void freeUpRoom(int theRoomNum) {
      kennelRooms[theRoomNum].setTrainable(null);
      // 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();
         freeUpRoom(theRoomNum);
         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
        freeUpRoom(theRoomNum);
        throw new RemoteException("lease expired", new
         UnknownLeaseException("expired!"));
      }

      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.
      }
   } 

// MAIN METHOD WHICH REGISTERS THIS PROVIDER WITH RMI
// REGISTRY OR JINI LOOKUP
   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");
        e.printStackTrace();

       }
    } 
    

}