599 lines · 19.5 KB · Java
RawDownload
/* * Copyright (c) 1999, 2010, 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 com.sun.jndi.rmi.registry;  import java.util.Hashtable;import java.util.Properties;import java.rmi.*;import java.rmi.server.*;import java.rmi.registry.Registry;import java.rmi.registry.LocateRegistry; import javax.naming.*;import javax.naming.spi.NamingManager;  /** * A RegistryContext is a context representing a remote RMI registry. * * @author Scott Seligman */  public class RegistryContext implements Context, Referenceable {     private Hashtable environment;    private Registry registry;    private String host;    private int port;    private static final NameParser nameParser = new AtomicNameParser();    private static final String SOCKET_FACTORY = "com.sun.jndi.rmi.factory.socket";     Reference reference = null; // ref used to create this context, if any     // Environment property that, if set, indicates that a security    // manager should be installed (if none is already in place).    public static final String SECURITY_MGR =            "java.naming.rmi.security.manager";     /**     * Returns a context for the registry at a given host and port.     * If "host" is null, uses default host.     * If "port" is non-positive, uses default port.     * Cloning of "env" is handled by caller; see comments within     * RegistryContextFactory.getObjectInstance(), for example.     */    public RegistryContext(String host, int port, Hashtable env)            throws NamingException    {        environment = ((env == null) ? new Hashtable(5) : env);        if (environment.get(SECURITY_MGR) != null) {            installSecurityMgr();        }         // chop off '[' and ']' in an IPv6 literal address        if ((host != null) && (host.charAt(0) == '[')) {            host = host.substring(1, host.length() - 1);        }         RMIClientSocketFactory socketFactory =                (RMIClientSocketFactory) environment.get(SOCKET_FACTORY);        registry = getRegistry(host, port, socketFactory);        this.host = host;        this.port = port;    }     /**     * Returns a clone of a registry context.  The context's private state     * is independent of the original's (so closing one context, for example,     * won't close the other).     */    // %%% Alternatively, this could be done with a clone() method.    RegistryContext(RegistryContext ctx) {        environment = (Hashtable)ctx.environment.clone();        registry = ctx.registry;        host = ctx.host;        port = ctx.port;        reference = ctx.reference;    }     protected void finalize() {        close();    }     public Object lookup(Name name) throws NamingException {        if (name.isEmpty()) {            return (new RegistryContext(this));        }        Remote obj;        try {            obj = registry.lookup(name.get(0));        } catch (NotBoundException e) {            throw (new NameNotFoundException(name.get(0)));        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }        return (decodeObject(obj, name.getPrefix(1)));    }     public Object lookup(String name) throws NamingException {        return lookup(new CompositeName(name));    }     /**     * If the object to be bound is both Remote and Referenceable, binds the     * object itself, not its Reference.     */    public void bind(Name name, Object obj) throws NamingException {        if (name.isEmpty()) {            throw (new InvalidNameException(                    "RegistryContext: Cannot bind empty name"));        }        try {            registry.bind(name.get(0), encodeObject(obj, name.getPrefix(1)));        } catch (AlreadyBoundException e) {            NamingException ne = new NameAlreadyBoundException(name.get(0));            ne.setRootCause(e);            throw ne;        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }    }     public void bind(String name, Object obj) throws NamingException {        bind(new CompositeName(name), obj);    }     public void rebind(Name name, Object obj) throws NamingException {        if (name.isEmpty()) {            throw (new InvalidNameException(                    "RegistryContext: Cannot rebind empty name"));        }        try {            registry.rebind(name.get(0), encodeObject(obj, name.getPrefix(1)));        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }    }     public void rebind(String name, Object obj) throws NamingException {        rebind(new CompositeName(name), obj);    }     public void unbind(Name name) throws NamingException {        if (name.isEmpty()) {            throw (new InvalidNameException(                    "RegistryContext: Cannot unbind empty name"));        }        try {            registry.unbind(name.get(0));        } catch (NotBoundException e) {            // method is idempotent        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }    }     public void unbind(String name) throws NamingException {        unbind(new CompositeName(name));    }     /**     * Rename is implemented by this sequence of operations:     * lookup, bind, unbind.  The sequence is not performed atomically.     */    public void rename(Name oldName, Name newName) throws NamingException {        bind(newName, lookup(oldName));        unbind(oldName);    }     public void rename(String name, String newName) throws NamingException {        rename(new CompositeName(name), new CompositeName(newName));    }     public NamingEnumeration list(Name name)    throws NamingException {        if (!name.isEmpty()) {            throw (new InvalidNameException(                    "RegistryContext: can only list \"\""));        }        try {            String[] names = registry.list();            return (new NameClassPairEnumeration(names));        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }    }     public NamingEnumeration list(String name) throws NamingException {        return list(new CompositeName(name));    }     public NamingEnumeration listBindings(Name name)            throws NamingException    {        if (!name.isEmpty()) {            throw (new InvalidNameException(                    "RegistryContext: can only list \"\""));        }        try {            String[] names = registry.list();            return (new BindingEnumeration(this, names));        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }    }     public NamingEnumeration listBindings(String name) throws NamingException {        return listBindings(new CompositeName(name));    }     public void destroySubcontext(Name name) throws NamingException {        throw (new OperationNotSupportedException());    }     public void destroySubcontext(String name) throws NamingException {        throw (new OperationNotSupportedException());    }     public Context createSubcontext(Name name) throws NamingException {        throw (new OperationNotSupportedException());    }     public Context createSubcontext(String name) throws NamingException {        throw (new OperationNotSupportedException());    }     public Object lookupLink(Name name) throws NamingException {        return lookup(name);    }     public Object lookupLink(String name) throws NamingException {        return lookup(name);    }     public NameParser getNameParser(Name name) throws NamingException {        return nameParser;    }     public NameParser getNameParser(String name) throws NamingException {        return nameParser;    }     public Name composeName(Name name, Name prefix) throws NamingException {        Name result = (Name)prefix.clone();        return result.addAll(name);    }     public String composeName(String name, String prefix)            throws NamingException    {        return composeName(new CompositeName(name),                           new CompositeName(prefix)).toString();    }     public Object removeFromEnvironment(String propName)            throws NamingException    {        return environment.remove(propName);    }     public Object addToEnvironment(String propName, Object propVal)            throws NamingException    {        if (propName.equals(SECURITY_MGR)) {            installSecurityMgr();        }        return environment.put(propName, propVal);    }     public Hashtable getEnvironment() throws NamingException {        return (Hashtable)environment.clone();    }     public void close() {        environment = null;        registry = null;        // &&& If we were caching registry connections, we would probably        // uncache this one now.    }     public String getNameInNamespace() {        return ""; // Registry has an empty name    }     /**     * Returns an RMI registry reference for this context.     *<p>     * If this context was created from a reference, that reference is     * returned.  Otherwise, an exception is thrown if the registry's     * host is "localhost" or the default (null).  Although this could     * possibly make for a valid reference, it's far more likely to be     * an easily made error.     *     * @see RegistryContextFactory     */    public Reference getReference() throws NamingException {        if (reference != null) {            return (Reference)reference.clone();  // %%% clone the addrs too?        }        if (host == null || host.equals("localhost")) {            throw (new ConfigurationException(                    "Cannot create a reference for an RMI registry whose " +                    "host was unspecified or specified as \"localhost\""));        }        String url = "rmi://";         // Enclose IPv6 literal address in '[' and ']'        url = (host.indexOf(":") > -1) ? url + "[" + host + "]" :                                         url + host;        if (port > 0) {            url += ":" + Integer.toString(port);        }        RefAddr addr = new StringRefAddr(RegistryContextFactory.ADDRESS_TYPE,                                         url);        return (new Reference(RegistryContext.class.getName(),                              addr,                              RegistryContextFactory.class.getName(),                              null));    }      /**     * Wrap a RemoteException inside a NamingException.     */    public static NamingException wrapRemoteException(RemoteException re) {         NamingException ne;         if (re instanceof ConnectException) {            ne = new ServiceUnavailableException();         } else if (re instanceof AccessException) {            ne = new NoPermissionException();         } else if (re instanceof StubNotFoundException ||                   re instanceof UnknownHostException ||                   re instanceof SocketSecurityException) {            ne = new ConfigurationException();         } else if (re instanceof ExportException ||                   re instanceof ConnectIOException ||                   re instanceof MarshalException ||                   re instanceof UnmarshalException ||                   re instanceof NoSuchObjectException) {            ne = new CommunicationException();         } else if (re instanceof ServerException &&                   re.detail instanceof RemoteException) {            ne = wrapRemoteException((RemoteException)re.detail);         } else {            ne = new NamingException();        }        ne.setRootCause(re);        return ne;    }     /**     * Returns the registry at a given host, port and socket factory.     * If "host" is null, uses default host.     * If "port" is non-positive, uses default port.     * If "socketFactory" is null, uses the default socket.     */    private static Registry getRegistry(String host, int port,                RMIClientSocketFactory socketFactory)            throws NamingException    {        // %%% We could cache registry connections here.  The transport layer        // may already reuse connections.        try {            if (socketFactory == null) {                return LocateRegistry.getRegistry(host, port);            } else {                return LocateRegistry.getRegistry(host, port, socketFactory);            }        } catch (RemoteException e) {            throw (NamingException)wrapRemoteException(e).fillInStackTrace();        }    }     /**     * Attempts to install a security manager if none is currently in     * place.     */    private static void installSecurityMgr() {         try {            System.setSecurityManager(new RMISecurityManager());        } catch (Exception e) {        }    }     /**     * Encodes an object prior to binding it in the registry.  First,     * NamingManager.getStateToBind() is invoked.  If the resulting     * object is Remote, it is returned.  If it is a Reference or     * Referenceable, the reference is wrapped in a Remote object.     * Otherwise, an exception is thrown.     *     * @param name      The object's name relative to this context.     */    private Remote encodeObject(Object obj, Name name)            throws NamingException, RemoteException    {        obj = NamingManager.getStateToBind(obj, name, this, environment);         if (obj instanceof Remote) {            return (Remote)obj;        }        if (obj instanceof Reference) {            return (new ReferenceWrapper((Reference)obj));        }        if (obj instanceof Referenceable) {            return (new ReferenceWrapper(((Referenceable)obj).getReference()));        }        throw (new IllegalArgumentException(                "RegistryContext: " +                "object to bind must be Remote, Reference, or Referenceable"));    }     /**     * Decodes an object that has been retrieved from the registry.     * First, if the object is a RemoteReference, the Reference is     * unwrapped.  Then, NamingManager.getObjectInstance() is invoked.     *     * @param name      The object's name relative to this context.     */    private Object decodeObject(Remote r, Name name) throws NamingException {        try {            Object obj = (r instanceof RemoteReference)                        ? ((RemoteReference)r).getReference()                        : (Object)r;            return NamingManager.getObjectInstance(obj, name, this,                                                   environment);        } catch (NamingException e) {            throw e;        } catch (RemoteException e) {            throw (NamingException)                wrapRemoteException(e).fillInStackTrace();        } catch (Exception e) {            NamingException ne = new NamingException();            ne.setRootCause(e);            throw ne;        }    } }  /** * A name parser for case-sensitive atomic names. */class AtomicNameParser implements NameParser {    private static final Properties syntax = new Properties();     public Name parse(String name) throws NamingException {        return (new CompoundName(name, syntax));    }}  /** * An enumeration of name / class-name pairs.  Since we don't know anything * about the classes, each class name is returned as the generic * "java.lang.Object". */class NameClassPairEnumeration implements NamingEnumeration {    private final String[] names;    private int nextName;       // index into "names"     NameClassPairEnumeration(String[] names) {        this.names = names;        nextName = 0;    }     public boolean hasMore() {        return (nextName < names.length);

Lines 1–500 of 599.