/*
*
* Copyright (c) 2000 Scott Oaks and Henry Wong. All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for NON-COMMERCIAL purposes and
* without fee is hereby granted.
*
* This sample source code is provided for example only,
* on an unsupported, as-is basis.
*
* AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
* THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE, OR NON-INFRINGEMENT. AUTHOR SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
*
* THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
* CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
* PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
* NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
* SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
* SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
* PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). AUTHOR
* SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
* HIGH RISK ACTIVITIES.
*/
import java.util.*;
import java.io.*;
import java.rmi.*;
import java.rmi.server.*;
import net.jini.discovery.*;
import net.jini.core.lookup.*;
import net.jini.core.lease.*;
import net.jini.core.event.*;
import com.sun.jini.lookup.*;
import com.sun.jini.reliableLog.*;
public class ConvertServiceImpl extends UnicastRemoteObject
implements ConvertServiceProxy, ServiceIDListener {
private ServerLandlord lord;
private ServerDelivery sender;
private ConvertServiceLogHandler handler;
private ReliableLog log;
private long seqNo;
private ServiceID id;
// This class holds the information necessary for an update.
// If we had other data to update at the same time as the
// sequence number, we'd bundle it into this class. If we had
// other data to update at another time, we'd create a different
// class.
private static class ConvertServiceUpdateRecord implements Serializable {
long seqNo;
}
// This class reads and writes the reliable log
class ConvertServiceLogHandler extends LogHandler {
public void snapshot(OutputStream os) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(os);
Object target;
if (id == null)
// write a dummy object
target = new String();
else target = id;
oos.writeObject(target);
oos.writeLong(seqNo);
oos.flush(); // Make sure it all gets to disk
}
public void recover(InputStream is) throws Exception {
ObjectInputStream ois = new ObjectInputStream(is);
Object target;
try {
target = ois.readObject();
} catch (Exception e) {
// no log
return;
}
if (target instanceof ServiceID)
id = (ServiceID) target;
// else it was the dummy string
seqNo = ois.readLong();
}
// Called when reading an update; the update was written
// as a ConvertServiceUpdateRecord
public void applyUpdate(Object o) {
if (o instanceof ConvertServiceUpdateRecord)
seqNo = ((ConvertServiceUpdateRecord) o).seqNo;
else throw new IllegalArgumentException("Unexpected update");
}
}
public ConvertServiceImpl(String logDir) throws RemoteException {
handler = new ConvertServiceLogHandler();
try {
ConvertServiceUpdateRecord csur = new ConvertServiceUpdateRecord();
log = new ReliableLog(logDir, handler);
log.recover();
log.snapshot(); // Clean out all past updates
} catch (Exception e) {
throw new RemoteException("Can't create log", e);
}
lord = new ServerLandlord();
sender = new ServerDelivery(this, lord);
}
public ConvertServiceRegistration getInstance(long duration) {
Hashtable ht = new Hashtable(13);
return new ConvertServiceRegistrationImpl(this, lord.newLease(ht, duration));
}
// To convert, first check the cache for previous results. If
// there's no cache, the landlord has expired the lease. If
// there's no data in the cache, calculcate the data and put it there
public String convert(Lease l, int i) throws LeaseDeniedException {
Hashtable cache = (Hashtable) lord.getSessionData(l);
if (cache == null)
throw new LeaseDeniedException("Lease expired");
Integer I = new Integer(i);
String s;
s = (String) cache.get(I);
if (s == null) {
s = I.toString();
cache.put(I, s);
}
sender.deliver(i, getNextSeq());
return s;
}
public synchronized EventRegistration
trackConversions(long duration,
RemoteEventListener rel, MarshalledObject key) {
return sender.addListener(rel, duration, key, seqNo);
}
private synchronized long getNextSeq() {
seqNo++;
try {
// Update the log with the new seq no; we must wrap
// this into an object for the update method
ConvertServiceUpdateRecord csur = new ConvertServiceUpdateRecord();
csur.seqNo = this.seqNo;
log.update(csur, true);
} catch (Exception e) {
e.printStackTrace();
}
return seqNo;
}
public void serviceIDNotify(ServiceID id) {
this.id = id;
try {
log.snapshot();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
System.setSecurityManager(new RMISecurityManager());
String[] groups = new String[] { "" };
// Create the instance of the service; the JoinManager will
// register it and renew its leases with the lookup service
ConvertServiceImpl csi = (ConvertServiceImpl) new ConvertServiceImpl("csiLog");
JoinManager manager = null;
if (csi.id != null)
manager = new JoinManager(csi.id, csi, null, groups, null, null);
else manager = new JoinManager(csi, null, groups, null, csi, null);
}
}
|