--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,360 @@
+/*
+ * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.rmi.registry;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.io.IOException;
+import java.net.*;
+import java.rmi.*;
+import java.rmi.server.ObjID;
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.security.PrivilegedActionException;
+import java.text.MessageFormat;
+import sun.rmi.server.UnicastServerRef;
+import sun.rmi.server.UnicastServerRef2;
+import sun.rmi.transport.LiveRef;
+import sun.rmi.transport.ObjectTable;
+import sun.rmi.transport.Target;
+
+/**
+ * A "registry" exists on every node that allows RMI connections to
+ * servers on that node. The registry on a particular node contains a
+ * transient database that maps names to remote objects. When the
+ * node boots, the registry database is empty. The names stored in the
+ * registry are pure and are not parsed. A service storing itself in
+ * the registry may want to prefix its name of the service by a package
+ * name (although not required), to reduce name collisions in the
+ * registry.
+ *
+ * The LocateRegistry class is used to obtain registry for different hosts.
+ *
+ * @see java.rmi.registry.LocateRegistry
+ */
+public class RegistryImpl extends java.rmi.server.RemoteServer
+ implements Registry
+{
+
+ /* indicate compatibility with JDK 1.1.x version of class */
+ private static final long serialVersionUID = 4666870661827494597L;
+ private Hashtable bindings = new Hashtable(101);
+ private static Hashtable allowedAccessCache = new Hashtable(3);
+ private static RegistryImpl registry;
+ private static ObjID id = new ObjID(ObjID.REGISTRY_ID);
+
+ private static ResourceBundle resources = null;
+
+ /**
+ * Construct a new RegistryImpl on the specified port with the
+ * given custom socket factory pair.
+ */
+ public RegistryImpl(int port,
+ RMIClientSocketFactory csf,
+ RMIServerSocketFactory ssf)
+ throws RemoteException
+ {
+ LiveRef lref = new LiveRef(id, port, csf, ssf);
+ setup(new UnicastServerRef2(lref));
+ }
+
+ /**
+ * Construct a new RegistryImpl on the specified port.
+ */
+ public RegistryImpl(int port)
+ throws RemoteException
+ {
+ LiveRef lref = new LiveRef(id, port);
+ setup(new UnicastServerRef(lref));
+ }
+
+ /*
+ * Create the export the object using the parameter
+ * <code>uref</code>
+ */
+ private void setup(UnicastServerRef uref)
+ throws RemoteException
+ {
+ /* Server ref must be created and assigned before remote
+ * object 'this' can be exported.
+ */
+ ref = uref;
+ uref.exportObject(this, null, true);
+ }
+
+ /**
+ * Returns the remote object for specified name in the registry.
+ * @exception RemoteException If remote operation failed.
+ * @exception NotBound If name is not currently bound.
+ */
+ public Remote lookup(String name)
+ throws RemoteException, NotBoundException
+ {
+ synchronized (bindings) {
+ Remote obj = (Remote)bindings.get(name);
+ if (obj == null)
+ throw new NotBoundException(name);
+ return obj;
+ }
+ }
+
+ /**
+ * Binds the name to the specified remote object.
+ * @exception RemoteException If remote operation failed.
+ * @exception AlreadyBoundException If name is already bound.
+ */
+ public void bind(String name, Remote obj)
+ throws RemoteException, AlreadyBoundException, AccessException
+ {
+ checkAccess("Registry.bind");
+ synchronized (bindings) {
+ Remote curr = (Remote)bindings.get(name);
+ if (curr != null)
+ throw new AlreadyBoundException(name);
+ bindings.put(name, obj);
+ }
+ }
+
+ /**
+ * Unbind the name.
+ * @exception RemoteException If remote operation failed.
+ * @exception NotBound If name is not currently bound.
+ */
+ public void unbind(String name)
+ throws RemoteException, NotBoundException, AccessException
+ {
+ checkAccess("Registry.unbind");
+ synchronized (bindings) {
+ Remote obj = (Remote)bindings.get(name);
+ if (obj == null)
+ throw new NotBoundException(name);
+ bindings.remove(name);
+ }
+ }
+
+ /**
+ * Rebind the name to a new object, replaces any existing binding.
+ * @exception RemoteException If remote operation failed.
+ */
+ public void rebind(String name, Remote obj)
+ throws RemoteException, AccessException
+ {
+ checkAccess("Registry.rebind");
+ bindings.put(name, obj);
+ }
+
+ /**
+ * Returns an enumeration of the names in the registry.
+ * @exception RemoteException If remote operation failed.
+ */
+ public String[] list()
+ throws RemoteException
+ {
+ String[] names;
+ synchronized (bindings) {
+ int i = bindings.size();
+ names = new String[i];
+ Enumeration enum_ = bindings.keys();
+ while ((--i) >= 0)
+ names[i] = (String)enum_.nextElement();
+ }
+ return names;
+ }
+
+ /**
+ * Check that the caller has access to perform indicated operation.
+ * The client must be on same the same host as this server.
+ */
+ public static void checkAccess(String op) throws AccessException {
+
+ try {
+ /*
+ * Get client host that this registry operation was made from.
+ */
+ final String clientHostName = getClientHost();
+ InetAddress clientHost;
+
+ try {
+ clientHost = (InetAddress)
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedExceptionAction() {
+ public Object run()
+ throws java.net.UnknownHostException
+ {
+ return InetAddress.getByName(clientHostName);
+ }
+ });
+ } catch (PrivilegedActionException pae) {
+ throw (java.net.UnknownHostException) pae.getException();
+ }
+
+ // if client not yet seen, make sure client allowed access
+ if (allowedAccessCache.get(clientHost) == null) {
+
+ if (clientHost.isAnyLocalAddress()) {
+ throw new AccessException(
+ "Registry." + op + " disallowed; origin unknown");
+ }
+
+ try {
+ final InetAddress finalClientHost = clientHost;
+
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedExceptionAction() {
+ public Object run() throws java.io.IOException {
+ /*
+ * if a ServerSocket can be bound to the client's
+ * address then that address must be local
+ */
+ (new ServerSocket(0, 10, finalClientHost)).close();
+ allowedAccessCache.put(finalClientHost,
+ finalClientHost);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException pae) {
+ // must have been an IOException
+
+ throw new AccessException(
+ "Registry." + op + " disallowed; origin " +
+ clientHost + " is non-local host");
+ }
+ }
+ } catch (ServerNotActiveException ex) {
+ /*
+ * Local call from this VM: allow access.
+ */
+ } catch (java.net.UnknownHostException ex) {
+ throw new AccessException("Registry." + op +
+ " disallowed; origin is unknown host");
+ }
+ }
+
+ public static ObjID getID() {
+ return id;
+ }
+
+ /**
+ * Retrieves text resources from the locale-specific properties file.
+ */
+ private static String getTextResource(String key) {
+ if (resources == null) {
+ try {
+ resources = ResourceBundle.getBundle(
+ "sun.rmi.registry.resources.rmiregistry");
+ } catch (MissingResourceException mre) {
+ }
+ if (resources == null) {
+ // throwing an Error is a bit extreme, methinks
+ return ("[missing resource file: " + key + "]");
+ }
+ }
+
+ String val = null;
+ try {
+ val = resources.getString(key);
+ } catch (MissingResourceException mre) {
+ }
+
+ if (val == null) {
+ return ("[missing resource: " + key + "]");
+ } else {
+ return (val);
+ }
+ }
+
+ /**
+ * Main program to start a registry. <br>
+ * The port number can be specified on the command line.
+ */
+ public static void main(String args[])
+ {
+ // Create and install the security manager if one is not installed
+ // already.
+ if (System.getSecurityManager() == null) {
+ System.setSecurityManager(new RMISecurityManager());
+ }
+
+ try {
+ /*
+ * Fix bugid 4147561: When JDK tools are executed, the value of
+ * the CLASSPATH environment variable for the shell in which they
+ * were invoked is no longer incorporated into the application
+ * class path; CLASSPATH's only effect is to be the value of the
+ * system property "env.class.path". To preserve the previous
+ * (JDK1.1 and JDK1.2beta3) behavior of this tool, however, its
+ * CLASSPATH should still be considered when resolving classes
+ * being unmarshalled. To effect this old behavior, a class
+ * loader that loads from the file path specified in the
+ * "env.class.path" property is created and set to be the context
+ * class loader before the remote object is exported.
+ */
+ String envcp = System.getProperty("env.class.path");
+ if (envcp == null) {
+ envcp = "."; // preserve old default behavior
+ }
+ URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp);
+ ClassLoader cl = new URLClassLoader(urls);
+
+ /*
+ * Fix bugid 4242317: Classes defined by this class loader should
+ * be annotated with the value of the "java.rmi.server.codebase"
+ * property, not the "file:" URLs for the CLASSPATH elements.
+ */
+ sun.rmi.server.LoaderHandler.registerCodebaseLoader(cl);
+
+ Thread.currentThread().setContextClassLoader(cl);
+
+ int regPort = Registry.REGISTRY_PORT;
+ if (args.length >= 1) {
+ regPort = Integer.parseInt(args[0]);
+ }
+ registry = new RegistryImpl(regPort);
+ // prevent registry from exiting
+ while (true) {
+ try {
+ Thread.sleep(Long.MAX_VALUE);
+ } catch (InterruptedException e) {
+ }
+ }
+ } catch (NumberFormatException e) {
+ System.err.println(MessageFormat.format(
+ getTextResource("rmiregistry.port.badnumber"),
+ args[0] ));
+ System.err.println(MessageFormat.format(
+ getTextResource("rmiregistry.usage"),
+ "rmiregistry" ));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ System.exit(1);
+ }
+}