FileDocCategorySizeDatePackage
ServiceFinder.javaAPI DocExample6451Thu Mar 16 11:52:16 GMT 2000None

ServiceFinder.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.io.*;
import java.rmi.*;
import java.util.*;
import net.jini.discovery.*;
import net.jini.core.lookup.*;
import net.jini.core.entry.*;
import net.jini.core.event.*;
import net.jini.core.lease.*;
import com.sun.jini.lease.*;

public class ServiceFinder implements DiscoveryListener {
    private static String[] publicGroup = new String[] { "" };
    private ServiceItem returnObject = null;
    private Hashtable items = new Hashtable();

    private Hashtable leases = new Hashtable();
    private LeaseRenewalManager lrm;
    private ServiceFinderListener sfl;

    private LookupDiscovery reg;
    private ServiceTemplate template;

    public ServiceFinder(Class serviceInterface) throws IOException {
        this(publicGroup, serviceInterface, (Entry[])null);
    }

    public ServiceFinder(Class serviceInterface, Entry attribute)
                         throws IOException {
        this(publicGroup, serviceInterface, new Entry[] { attribute });
    }

    public ServiceFinder(Class serviceInterface, Entry[] attributes)
                         throws IOException {
        this(publicGroup, serviceInterface, attributes);
    }

    public ServiceFinder(String[] groups, Class serviceInterface,
                         Entry[] attributes) throws IOException {
        // Construct the template here for matching in the lookup service
        // We don't use the template until we actually discover a service
        Class[] name = new Class[] { serviceInterface };
        template = new ServiceTemplate(null, name, attributes);

        // Initialize for receiving events from the lookup service
        lrm = new LeaseRenewalManager();
        sfl = new ServiceFinderListener(this);

        // Create the facility to perform multicast discovery for all
        // lookup services
        reg = new LookupDiscovery(groups);
        reg.addDiscoveryListener(this);
    }

    // Automatically called when a lookup service is discovered
    // (the listener callback of the addDiscoveryListener method)
    public synchronized void discovered(DiscoveryEvent dev) {
        ServiceRegistrar[] lookup = dev.getRegistrars();
        // We may have discovered one or more lookup services
        for (int i = 0; i < lookup.length; i++) {
            try {
                EventRegistration reg = lookup[i].notify(template,
                		ServiceRegistrar.TRANSITION_NOMATCH_MATCH,
                		sfl, null, Lease.FOREVER);
		lrm.renewUntil(reg.getLease(), Lease.FOREVER, null);
		leases.put(lookup[i], reg);
	    } catch (RemoteException rex) {
	        System.out.println("Registration error " + rex);
	    }
	    try {
	        ServiceMatches items = lookup[i].lookup(template,
	        				Integer.MAX_VALUE);
                // Each lookup service may have zero or more registered
                // servers that implement our desired template
                for (int j = 0; j < items.items.length; j++) {
                    if (items.items[j].service != null)
                        // Put each matching service into our vector
                        addServiceItem(items.items[j]);
                    // else the service item couldn't be deserialized
                    // so the lookup() method skipped it
                }
            } catch (RemoteException ex) {
                System.out.println("ServiceFinder Error: " + ex);
            }
        }
    }

    // An error talking to a lookup service caused it to be discarded
    // Remove any references to it from our hashtable, and cancel
    // our leases to that service
    public synchronized void discarded(DiscoveryEvent dev) {
        ServiceRegistrar[] lookup = dev.getRegistrars();
        for (int i = 0; i < lookup.length; i++) {
            try {
                EventRegistration reg = (EventRegistration) leases.get(lookup[i]);
                if (reg != null) {
                    leases.remove(lookup[i]);
                    lrm.remove(reg.getLease());
                }
            } catch (UnknownLeaseException ule) {}
        }
    }

    public synchronized void addServiceItem(ServiceItem item) {
        items.put(item.serviceID, item);
        notifyAll();
    }

    // This class is to be used by the client. It will return only
    // the first service object that satisfies the template request.
    public synchronized Object getObject() {
        if (returnObject == null) {
            while (items.isEmpty()) {
                try {
                    wait();
	        } catch (InterruptedException ie) {}
	    }
	    returnObject = (ServiceItem) items.elements().nextElement();
        }
        return returnObject.service;
    }

    // If an error is encountered when using a service object, the client
    // should call this method.
    // A new object can then be gotten from the getObject() method.
    public synchronized void errored(Object obj) {
        if ((obj != null) && (returnObject != null)) {
            if (obj.equals(returnObject.service)) {
                items.remove(returnObject.serviceID);
		returnObject = null;
            }
        }
    }
}