FileDocCategorySizeDatePackage
ConvertServiceImpl.javaAPI DocExample6655Thu Mar 16 11:52:52 GMT 2000None

ConvertServiceImpl.java

/*
 *
 * 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);
    }
}