361 lines · 12.9 KB · Java
RawDownload
/* * Copyright (c) 1996, 2008, Oracle and/or its affiliates. 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.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<String, Remote> bindings        = new Hashtable<String, Remote>(101);    private static Hashtable<InetAddress, InetAddress> allowedAccessCache        = new Hashtable<InetAddress, InetAddress>(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 = 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 = 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 = 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 = java.security.AccessController.doPrivileged(                    new java.security.PrivilegedExceptionAction<InetAddress>() {                        public InetAddress 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<Void>() {                            public Void 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);    }}