ENTERPRISE JAVAHow to Use Jini Distributed Leasing
- By Kathy Kozel
- May 13, 2000
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();
}
}
}