/* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://www.sun.com/cddl/cddl.html or
* install_dir/legal/LICENSE
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at install_dir/legal/LICENSE.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id$
*
* Copyright 2005-2009 Sun Microsystems Inc. All Rights Reserved
*/
package com.sun.faban.common;
import java.rmi.RMISecurityManager;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Logger;
import java.util.logging.Level;
/**
* This class implements the Registry interface
* The Registry is the single remote object that runs on the master
* machine and with which all other instances of remote servers reregister.
* A remote reference to any remote service is obtained by the GUI as
* well as the Engine through the registry. There is only one remote
* server object (the Registry) that is known by rmiregistry running
* on the master machine. Once a reference to the Registry is obtained
* by the client, it should use the 'getReference' method to obtain a
* reference to any type of remote server.<p>
*
* Although the Registry implementation uses rmi underneath, the rmi registry
* is fully encapsulated inside the Registry and RegistryLocator to avoid any
* confusion in the agent programs and other programs accessing the registry.
*
* @author Shanti Subramanyam
*/
public class RegistryImpl extends UnicastRemoteObject implements Registry {
// This field is a legal requirement and serves no other purpose.
static final String COPYRIGHT =
"Copyright \251 2006-2009 Sun Microsystems, Inc., 4150 Network " +
"Circle, Santa Clara, California 95054, U.S.A. All rights " +
"reserved.\nU.S. Government Rights - Commercial software. " +
"Government users are subject to the Sun Microsystems, Inc. " +
"standard license agreement and applicable provisions of the FAR " +
"and its supplements.\n" +
"Use is subject to license terms.\n" +
"This distribution may include materials developed by third " +
"parties.\n" +
"Sun, Sun Microsystems, the Sun logo and Java are trademarks " +
"or registered trademarks of Sun Microsystems, Inc. in the U.S. " +
"and other countries.\n" +
"Apache is a trademark of The Apache Software Foundation, and is " +
"used with permission.\n" +
"This product is covered and controlled by U.S. Export Control " +
"laws and may be subject to the export or import laws in other " +
"countries. Nuclear, missile, chemical biological weapons or " +
"nuclear maritime end uses or end users, whether direct or " +
"indirect, are strictly prohibited. Export or reexport to " +
"countries subject to U.S. embargo or to entities identified on " +
"U.S. export exclusion lists, including, but not limited to, the " +
"denied persons and specially designated nationals lists is " +
"strictly prohibited.\n" +
"\n" +
"Copyright \251 2006-2009 Sun Microsystems, Inc., 4150 Network " +
"Circle, Santa Clara, California 95054, Etats-Unis. Tous droits " +
"r\351serv\351s.\n" +
"L'utilisation est soumise aux termes de la Licence.\n" +
"Cette distribution peut comprendre des composants " +
"d\351velopp\351s par des tierces parties.\n" +
"Sun, Sun Microsystems, le logo Sun et Java sont des marques " +
"de fabrique ou des marques d\351pos\351es de " +
"Sun Microsystems, Inc. aux Etats-Unis et dans d'autres pays.\n" +
"Apache est une marque d\264Apache Software Foundation, utilis\351e " +
"avec leur permission.\n" +
"Ce produit est soumis \340 la l\351gislation am\351ricaine " +
"en mati\350re de contr\364le des exportations et peut \352tre " +
"soumis \340 la r\350glementation en vigueur dans d'autres pays " +
"dans le domaine des exportations et importations. Les " +
"utilisations, ou utilisateurs finaux, pour des armes " +
"nucl\351aires, des missiles, des armes biologiques et chimiques " +
"ou du nucl\351aire maritime, directement ou indirectement, sont " +
"strictement interdites. Les exportations ou r\351exportations " +
"vers les pays sous embargo am\351ricain, ou vers des entit\351s " +
"figurant sur les listes d'exclusion d'exportation " +
"am\351ricaines, y compris, mais de mani\350re non exhaustive, " +
"la liste de personnes qui font objet d'un ordre de ne pas " +
"participer, d'une fa\347on directe ou indirecte, aux " +
"exportations des produits ou des services qui sont r\351gis par " +
"la l\351gislation am\351ricaine en mati\350re de contr\364le " +
"des exportations et la liste de ressortissants sp\351cifiquement " +
"d\351sign\351s, sont rigoureusement interdites.\n";
private static final long serialVersionUID = 20070523L;
static int rmiPort = RegistryLocator.DEFAULT_PORT;
private HashMap<String, Remote> servicesTable =
new HashMap<String, Remote>();
private HashMap<String, HashMap<String, Remote>> servicesTypeTable =
new HashMap<String, HashMap<String, Remote>>();
// private String className;
private static Logger logger =
Logger.getLogger(RegistryImpl.class.getName());
private RegistryImpl() throws RemoteException {
super();
}
/**
* Registers service with Registry.
* The service driverName is of the form <driverName>@<host>
* For example, a CmdAgent will reregister itself as CmdAgent@<host>
* so all CmdAgents on different machines can be uniquely
* identified by driverName.
*
* @param name public driverName of service
* @param service Remote reference to service
* @return true if registration succeeded, false if there is already
* an object registered by this name.
*/
public synchronized boolean register(String name, Remote service) {
if (servicesTable.get(name) == null) {
logger.info("Registering " + name + " on " + getCaller());
servicesTable.put(name, service);
return true;
} else {
logger.warning("Failed registering. Service " + name +
" already exists");
return false;
}
}
/**
* Registers service with Registry.
* The service driverName is of the form <driverName>@<host>
* For example, a CmdAgent will reregister itself as CmdAgent@<host>
* so all CmdAgents on different machines can be uniquely
* identified by driverName.
*
* @param type of service
* @param name of service
* @param service Remote reference to service
* @return true if registration succeeded, false if there is already
* an object registered by this name.
*/
public synchronized boolean register(String type, String name,
Remote service) {
if (service == null)
throw new NullPointerException("Type: " + type + ", Name: " +
name + "| Service reference is null");
// First check if the type of service exists
HashMap<String, Remote> h = servicesTypeTable.get(type);
if (h == null) {
h = new HashMap<String, Remote>();
servicesTypeTable.put(type, h);
} else if (h.get(name) != null) {
logger.warning("Failed registering. Service " + name +
" already exists");
return false;
}
logger.info("Registering " + name + " (type: " + type + ") on " +
getCaller());
h.put(name, service);
return true;
}
/**
* Re-registers service with Registry, replacing old entry if exists.
* The service driverName is of the form <driverName>@<host>
* For example, a CmdAgent will reregister itself as CmdAgent@<host>
* so all CmdAgents on different machiens can be uniquely
* identified by driverName.
* @param name public driverName of service
* @param service Remote reference to service
*/
public synchronized void reregister(String name, Remote service)
{
logger.info("Registering " + name + " on " + getCaller());
servicesTable.put(name, service);
}
/**
* Re-registers service with Registry, replacing old entry if exists.
* The service driverName is of the form <driverName>@<host>
* For example, a CmdAgent will reregister itself as CmdAgent@<host>
* so all CmdAgents on different machiens can be uniquely
* identified by driverName.
* @param type of service
* @param name of service
* @param service Remote reference to service
*/
public synchronized void reregister(String type, String name, Remote service) {
if (service == null)
throw new NullPointerException("Type: " + type + ", Name: " +
name + "| Service reference is null");
// First check if the type of service exists
HashMap<String, Remote> h = servicesTypeTable.get(type);
if (h == null) {
h = new HashMap<String, Remote>();
servicesTypeTable.put(type, h);
}
logger.info("Registering " + name + " (type: " + type + ") on " +
getCaller());
h.put(name, service);
}
/**
* unregister service from Registry
* The registry removes this service from its list and clients
* can no longer access it. This method is typically called when
* the service exits.
* @param name public driverName of service
*/
public synchronized void unregister(String name) {
logger.info("Unregistering " + name);
servicesTable.remove(name);
}
/**
* unregister service from Registry
* The registry removes this service from its list and clients
* can no longer access it. This method is typically called when
* the service exits.
* @param type of service
* @param name public driverName of service
*/
public synchronized void unregister(String type, String name) {
// First check if the type of service exists
HashMap<String, Remote> h = servicesTypeTable.get(type);
if (h == null) {
logger.warning("Registry.unregister : " +
"Cannot find Service type : " + type);
}
else {
logger.info("Unregistering " + name + "(type: " + type + ")");
h.remove(name);
}
}
/**
* get reference to service from Registry
* The registry searches in its list of registered services
* and returns a remote reference to the requested one.
* The service driverName is of the form <driverName>@<host>
* @param name public driverName of service
* @return remote reference
*/
public synchronized Remote getService(String name) {
logger.info("Get service by name: " + name);
return servicesTable.get(name);
}
/**
* get reference to service from Registry
* The registry searches in its list of registered services
* and returns a remote reference to the requested one.
* The service driverName is of the form <driverName>@<host>
* @param type of service
* @param name public driverName of service
* @return remote reference
*/
public synchronized Remote getService(String type, String name) {
logger.info("Get service by name: " + name + ", type: " + type);
Remote r = null;
// First check if the type of service exists
HashMap<String, Remote> h = servicesTypeTable.get(type);
if (h == null) {
logger.warning("Registry.getService : " +
"Cannot find Service type : " + type);
}
else {
r = h.get(name);
}
return r;
}
/**
* get all references to a type of services from Registry
* The registry searches in its list of registered services
* and returns all remote references to the requested type.
* The service driverName is of the form <driverName>@<host>
* @param type of service
* @return remote references
*/
public synchronized Remote[] getServices(String type) {
logger.info("Get services by type: " + type);
Remote[] r = null;
// First check if the type of service exists
HashMap<String, Remote> h = servicesTypeTable.get(type);
if (h == null) {
logger.warning("Registry.getServices : " +
"Cannot find Service type : " + type);
}
else {
r = new Remote[h.size()];
r = h.values().toArray(r);
}
return r;
}
/**
* Get the number of registered Services of a type.
* @param type of service
* @return int number of registered services
*/
public synchronized int getNumServices(String type) {
// First check if the type of service exists
HashMap<String, Remote> h = servicesTypeTable.get(type);
int i = 0;
if (h == null) {
logger.warning("Registry.getNumServices : " +
"Cannot find Service type : " + type);
}
else {
i = h.size();
}
return i;
}
// Get the caller
private String getCaller() {
String s = null;
try {
s = getClientHost();
}
catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
}
return s;
}
/**
* Kill is called to exit the RMI registry and Registry.
*/
public void kill() {
logger.info("Unregistering Services");
for (Iterator<String> iter = servicesTable.keySet().iterator();
iter.hasNext();) {
logger.fine("Unregistering " + iter.next());
iter.remove();
}
for (Iterator<String> iter = servicesTypeTable.keySet().iterator();
iter.hasNext();) {
logger.fine("Unregistering " + iter.next());
iter.remove();
}
// *** This is to gracefully return from this method.
// *** The Agent will exit after 5 seconds
// *** If the System.exit(0) is called in this method
// *** the Service will get a RemoteException
Thread exitThread = new Thread() {
public void run() {
try {
Thread.sleep(5000);
System.exit(0);
}
catch(Exception e) {}
}
};
exitThread.start();
logger.info("Registry will exit in 5 secs");
}
/**
* Registration for RMI serving.
*
* @param args Command line arguments, not used
*/
public static void main(String[] args) {
String portString = System.getProperty("faban.registry.port");
if (portString != null)
try {
rmiPort = Integer.parseInt(portString);
} catch (NumberFormatException e) {
System.err.println("Property faban.registry.port " +
e.getMessage());
e.printStackTrace();
System.exit(-1);
}
java.rmi.registry.Registry rmiRegistry = null;
try {
rmiRegistry = LocateRegistry.createRegistry(rmiPort);
logger.fine("Registry listening on port " +
rmiPort + ".");
} catch (Exception e) {
logger.log(Level.SEVERE, "Exception starting registry.", e);
System.exit(-1);
}
System.setSecurityManager (new RMISecurityManager());
try {
Registry registry = new RegistryImpl();
rmiRegistry.bind(RegistryLocator.BIND_NAME, registry);
// debug.println(3, "Binding registry to " + s);
// If the debug level is set to too high and if this is not
// printed driver will hang !!!!
logger.info("Registry started.");
}
catch (Exception e) {
e.printStackTrace();
try {
rmiRegistry.unbind(RegistryLocator.BIND_NAME);
}
catch (Exception ei) { }
System.exit(-1);
}
}
}