You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2006/08/22 17:06:07 UTC

svn commit: r433660 [2/2] - in /incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider: ./ rmi/ rmi/registry/

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContext.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContext.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContext.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContext.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,769 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.4 $
+ */
+package org.apache.harmony.jndi.provider.rmi.registry;
+
+import java.rmi.AccessException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.ConnectException;
+import java.rmi.ConnectIOException;
+import java.rmi.MarshalException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.NotBoundException;
+import java.rmi.RMISecurityManager;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.ServerException;
+import java.rmi.StubNotFoundException;
+import java.rmi.UnknownHostException;
+import java.rmi.UnmarshalException;
+
+import java.rmi.activation.ActivateFailedException;
+
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+
+import java.rmi.server.ExportException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.SkeletonMismatchException;
+import java.rmi.server.SkeletonNotFoundException;
+
+import java.util.Hashtable;
+
+import javax.naming.CommunicationException;
+import javax.naming.CompositeName;
+import javax.naming.ConfigurationException;
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NoPermissionException;
+import javax.naming.NotContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.ServiceUnavailableException;
+import javax.naming.StringRefAddr;
+
+import javax.naming.spi.NamingManager;
+
+
+/**
+ * RMI Registry context implementation.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.4 $
+ */
+public class RegistryContext implements Context, Referenceable {
+
+    /**
+     * Constant that holds the name of the environment property
+     * for specifying that RMI security manager should be installed.
+     */
+    public static final String SECURITY_MANAGER =
+            "java.naming.rmi.security.manager";
+
+    /**
+     * Constant that holds the name of the environment property
+     * for specifying the name of {@link RMIClientSocketFactory} class.
+     */
+    public static final String CLIENT_SOCKET_FACTORY =
+            "org.apache.harmony.jndi.provider.rmi.registry.clientSocketFactory";
+
+    /**
+     * Prefix for RMI URLs.
+     */
+    public static final String RMI_URL_PREFIX = "rmi:";
+
+    /**
+     * Address type for RMI context references.
+     */
+    public static final String ADDRESS_TYPE = "URL";
+
+    /**
+     * Name parser.
+     */
+    protected static final NameParser nameParser = new AtomicNameParser();
+
+    /**
+     * Registry host, stored to produce copies of this context.
+     */
+    protected String host;
+
+    /**
+     * Registry port, stored to produce copies of this context.
+     */
+    protected int port;
+
+    /**
+     * RMI client socket factory, stored to produce copies of this context.
+     */
+    protected RMIClientSocketFactory csf;
+
+    /**
+     * Local environment.
+     */
+    protected Hashtable environment;
+
+    /**
+     * RMI Registry.
+     */
+    protected Registry registry;
+
+    /**
+     * Reference for this context, initialized by
+     * {@link RegistryContextFactory#getObjectInstance(Object, Name, Context, Hashtable)}.
+     */
+    protected Reference reference;
+
+    /**
+     * Creates RMI registry context bound to RMI Registry
+     * operating on the specified host and port.
+     *
+     * @param   host
+     *          Host. If <code>null</code>, localhost is assumed.
+     *
+     * @param   port
+     *          Port. If <code>0</code>, default registry port
+     *          (<code>1099</code>) is assumed.
+     *
+     * @param   environment
+     *          Context environment, may be <code>null</code>
+     *          which denotes empty environment.
+     *
+     * @throws  NamingException
+     *          If some naming error occurs.
+     */
+    public RegistryContext(String host, int port, Hashtable environment)
+            throws NamingException {
+        this.host = host;
+        this.port = port;
+
+        this.environment = ((environment != null)
+                ? (Hashtable) environment.clone()
+                : new Hashtable());
+
+        if (this.environment.get(SECURITY_MANAGER) != null) {
+            installSecurityManager();
+        }
+
+        String clientSocketFactoryName = (String)
+                this.environment.get(CLIENT_SOCKET_FACTORY);
+
+        if (clientSocketFactoryName == null) {
+            csf = null;
+        } else {
+            try {
+                csf = (RMIClientSocketFactory) Class.forName(
+                        clientSocketFactoryName, true, Thread.currentThread()
+                                .getContextClassLoader()).newInstance();
+            } catch (ClassNotFoundException e) {
+                throw (ConfigurationException) new ConfigurationException(
+                        "RMI Client Socket Factory cannot be instantiated")
+                                .initCause(e);
+            } catch (InstantiationException e) {
+                throw (ConfigurationException) new ConfigurationException(
+                        "RMI Client Socket Factory cannot be instantiated")
+                                .initCause(e);
+            } catch (IllegalAccessException e) {
+                throw (NoPermissionException) new NoPermissionException(
+                        "RMI Client Socket Factory cannot be instantiated")
+                                .initCause(e);
+            }
+        }
+        registry = getRegistry(host, port, csf);
+        reference = null;
+    }
+
+    /**
+     * Creates RMI registry context by copying the specified context.
+     *
+     * @param   context
+     *          Context to copy.
+     */
+    protected RegistryContext(RegistryContext context) {
+        host = context.host;
+        port = context.port;
+        csf = context.csf;
+        environment = (Hashtable) context.environment.clone();
+        registry = context.registry;
+        reference = context.reference;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object lookup(Name name) throws NamingException {
+        if (name.isEmpty()) {
+            return cloneContext();
+        }
+        String stringName = getMyComponents(name);
+
+        try {
+            return getObjectInstance(stringName, registry.lookup(stringName));
+        } catch (NotBoundException e) {
+            throw (NameNotFoundException) new NameNotFoundException(
+                    "Name is not bound: " + stringName).initCause(e);
+        } catch (RemoteException e) {
+            throw (NamingException) newNamingException(e).fillInStackTrace();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object lookup(String name) throws NamingException {
+        return lookup(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object lookupLink(Name name) throws NamingException {
+        return lookup(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object lookupLink(String name) throws NamingException {
+        return lookupLink(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind(Name name, Object obj) throws NamingException {
+        if (name.isEmpty()) {
+            throw new InvalidNameException("Cannot bind empty name");
+        }
+        String stringName = getMyComponents(name);
+
+        try {
+            registry.bind(stringName, getStateToBind(stringName, obj));
+        } catch (AlreadyBoundException e) {
+            throw (NameAlreadyBoundException) new NameAlreadyBoundException(
+                    "Name is already bound: " + stringName).initCause(e);
+        } catch (RemoteException e) {
+            throw (NamingException) newNamingException(e).fillInStackTrace();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void bind(String name, Object obj) throws NamingException {
+        bind(new CompositeName(name), obj);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rebind(Name name, Object obj) throws NamingException {
+        if (name.isEmpty()) {
+            throw new InvalidNameException("Cannot rebind empty name");
+        }
+        String stringName = getMyComponents(name);
+
+        try {
+            registry.rebind(stringName, getStateToBind(stringName, obj));
+        } catch (RemoteException e) {
+            throw (NamingException) newNamingException(e).fillInStackTrace();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rebind(String name, Object obj) throws NamingException {
+        rebind(new CompositeName(name), obj);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unbind(Name name) throws NamingException {
+        if (name.isEmpty()) {
+            throw new InvalidNameException("Cannot unbind empty name");
+        }
+        String stringName = getMyComponents(name);
+
+        try {
+            registry.unbind(stringName);
+        } catch (NotBoundException e) {
+            // Returning ok if target name is not found, by the specification.
+        } catch (RemoteException e) {
+            throw (NamingException) newNamingException(e).fillInStackTrace();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void unbind(String name) throws NamingException {
+        unbind(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Context createSubcontext(Name name)
+            throws OperationNotSupportedException {
+        throw new OperationNotSupportedException("RMI Registry "
+                + "is a flat context and doesn't support subcontexts");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Context createSubcontext(String name) throws NamingException {
+        return createSubcontext(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void destroySubcontext(Name name)
+            throws OperationNotSupportedException {
+        throw new OperationNotSupportedException("RMI Registry "
+                + "is a flat context and doesn't support subcontexts");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void destroySubcontext(String name) throws NamingException {
+        destroySubcontext(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename(Name oldName, Name newName) throws NamingException {
+        bind(newName, lookup(oldName));
+        unbind(oldName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void rename(String oldName, String newName) throws NamingException {
+        rename(new CompositeName(oldName), new CompositeName(newName));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NamingEnumeration list(Name name) throws NamingException {
+        if (name.isEmpty()) {
+            try {
+                return new NameClassPairEnumeration(registry.list());
+            } catch (RemoteException e) {
+                throw (NamingException)
+                        newNamingException(e).fillInStackTrace();
+            }
+        } else {
+            Object obj = lookup(name);
+
+            if (obj instanceof Context) {
+                try {
+                    return ((Context) obj).list("");
+                } finally {
+                    ((Context) obj).close();
+                }
+            }
+            throw new NotContextException(
+                    "Name specifies an object that is not a context: " + name);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NamingEnumeration list(String name) throws NamingException {
+        return list(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NamingEnumeration listBindings(Name name) throws NamingException {
+        if (name.isEmpty()) {
+            try {
+                return new BindingEnumeration(registry.list(), this);
+            } catch (RemoteException e) {
+                throw (NamingException)
+                        newNamingException(e).fillInStackTrace();
+            }
+        } else {
+            Object obj = lookup(name);
+
+            if (obj instanceof Context) {
+                try {
+                    return ((Context) obj).listBindings("");
+                } finally {
+                    ((Context) obj).close();
+                }
+            }
+            throw new NotContextException(
+                    "Name specifies an object that is not a context: " + name);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NamingEnumeration listBindings(String name) throws NamingException {
+        return listBindings(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameParser getNameParser(Name name) {
+        return nameParser;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NameParser getNameParser(String name) throws NamingException {
+        return getNameParser(new CompositeName(name));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Name composeName(Name name, Name prefix) throws NamingException {
+        return ((Name) prefix.clone()).addAll(name);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String composeName(String name, String prefix)
+            throws NamingException {
+        return composeName(
+                new CompositeName(name), new CompositeName(prefix)).toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getNameInNamespace() {
+        return "";
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Hashtable getEnvironment() {
+        return (Hashtable) environment.clone();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object addToEnvironment(String propName, Object propVal)
+            throws NoPermissionException {
+        if (propName.equals(SECURITY_MANAGER)) {
+            installSecurityManager();
+        }
+        return environment.put(propName, propVal);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object removeFromEnvironment(String propName) {
+        return environment.remove(propName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void close() {
+        environment = null;
+        registry = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Reference getReference() throws NamingException {
+        if (reference == null) {
+            if ((host == null) || (host.equals("localhost"))) {
+                throw new ConfigurationException(
+                        "Cannot create reference for RMI registry "
+                        + "that is being accessed using localhost");
+            }
+            reference = new Reference(
+                    RegistryContext.class.getName(),
+                    new StringRefAddr(ADDRESS_TYPE, RMI_URL_PREFIX + "//"
+                            + host + ((port > 0) ? (":" + port) : "")),
+                    RegistryContextFactory.class.getName(), null);
+        }
+        return (Reference) reference.clone();
+    }
+
+    /**
+     * Initializes reference for this context instance. Called by
+     * {@link RegistryContextFactory#getObjectInstance(Object, Name, Context, Hashtable)}.
+     *
+     * @param   reference
+     *          Reference for this context instance.
+     */
+    protected void setReference(Reference reference) {
+        this.reference = reference;
+    }
+
+    /**
+     * Returns a clone of this context.
+     *
+     * @return  Clone of this context.
+     */
+    protected RegistryContext cloneContext() {
+        return new RegistryContext(this);
+    }
+
+    /**
+     * Verifies that the specified name is valid for this context
+     * and returns string representation of that name for this provider.
+     *
+     * Returns returns first component of a {@link CompositeName}
+     * or a string representation of a name otherwise.
+     *
+     * @param   name
+     *          Name to verify.
+     *
+     * @return  {@link CompositeName#get(int) CompositeName#get(0)}
+     *          if <code>name</code> is a {@link CompositeName},
+     *          {@link Object#toString() name.toString()} otherwise.
+     */
+    protected String getMyComponents(Name name) {
+        if (name instanceof CompositeName) {
+            return name.get(0);
+        } else {
+            return name.toString();
+        }
+    }
+
+    /**
+     * Prepares object for binding. It calls
+     * {@link NamingManager#getStateToBind(Object, Name, Context, Hashtable)}
+     * and makes the resulting object {@link Remote} by wrapping it into
+     * {@link RemoteReferenceWrapper}.
+     *
+     * @param   name
+     *          Object name.
+     *
+     * @param   obj
+     *          Object to prepare for binding.
+     *
+     * @return  Object ready for binding.
+     *
+     * @throws  NamingException
+     *          If some naming error occurs.
+     *
+     * @throws  RemoteException
+     *          If remote exception occurs.
+     */
+    protected Remote getStateToBind(String name, Object obj)
+            throws NamingException, RemoteException {
+        obj = NamingManager.getStateToBind(
+                obj, new CompositeName().add(name), this, environment);
+
+        if (obj instanceof Remote) {
+            return (Remote) obj;
+        }
+
+        if (obj instanceof Reference) {
+            return new RemoteReferenceWrapper((Reference) obj);
+        }
+
+        if (obj instanceof Referenceable) {
+            return new RemoteReferenceWrapper(
+                    ((Referenceable) obj).getReference());
+        }
+
+        throw new IllegalArgumentException("Cannot bind to RMI Registry object "
+                + "that is neither Remote nor Reference nor Referenceable");
+    }
+
+    /**
+     * Processes object returned from {@linkplain Registry RMI registry}.
+     * It unwraps {@link RemoteReference} if neccessary and calls
+     * {@link NamingManager#getObjectInstance(Object, Name, Context, Hashtable)}.
+     *
+     * @param   name
+     *          Object name.
+     *
+     * @param   remote
+     *          Returned object.
+     *
+     * @return  Processed object.
+     *
+     * @throws  NamingException
+     *          If some naming error occurs.
+     *
+     * @throws  RemoteException
+     *          If remote exception occurs.
+     */
+    protected Object getObjectInstance(String name, Remote remote)
+            throws NamingException, RemoteException {
+        Object obj;
+
+        obj = ((remote instanceof RemoteReference)
+                ? ((RemoteReference) remote).getReference()
+                : (Object) remote);
+
+        try {
+            return NamingManager.getObjectInstance(
+                    obj, new CompositeName().add(name), this, environment);
+        } catch (NamingException e) {
+            throw e;
+        } catch (RemoteException e) {
+            throw e;
+        } catch (Exception e) {
+            throw (NamingException) new NamingException(
+                    "NamingManager.getObjectInstance() failed").initCause(e);
+        }
+    }
+
+    /**
+     * Prepares a new {@link NamingException} wrapping the specified
+     * {@link RemoteException} source exception. Source exception becomes a
+     * {@linkplain NamingException#getCause() cause} of the generated exception.
+     *
+     * The particular subclass of {@link NamingException} returned depends
+     * on the particular subclass of source {@link RemoteException}.
+     *
+     * If source exception is not of a specific class or is not
+     * a {@link RemoteException} or is <code>null</code>,
+     * then plain {@link NamingException} is returned.
+     *
+     * Note: {@link Throwable#fillInStackTrace()} should be called before
+     * throwing the generated exception, to provide the proper
+     * (not including this method) stack trace for the exception.
+     *
+     * Example of use:
+     *
+     * <code>try {
+     *     ...
+     * } catch (RemoteException e) {
+     *     throw (NamingException) newNamingException(e).fillInStackTrace();
+     * }</code>
+     *
+     * @param   e
+     *          Source {@link RemoteException}.
+     *
+     * @return  Generated {@link NamingException} exception.
+     */
+    protected NamingException newNamingException(Throwable e) {
+        NamingException ret =
+                  (e instanceof AccessException)
+                        ? new NoPermissionException()
+                : (e instanceof ConnectException)
+                        ? new ServiceUnavailableException()
+                : (e instanceof ConnectIOException)
+               || (e instanceof ExportException)
+               || (e instanceof MarshalException)
+               || (e instanceof UnmarshalException)
+                        ? new CommunicationException()
+                : (e instanceof ActivateFailedException)
+               || (e instanceof NoSuchObjectException)
+               || (e instanceof SkeletonMismatchException)
+               || (e instanceof SkeletonNotFoundException)
+               || (e instanceof StubNotFoundException)
+               || (e instanceof UnknownHostException)
+                        ? new ConfigurationException()
+                : (e instanceof ServerException)
+                        ? newNamingException(e.getCause())
+                        : new NamingException();
+
+        if (ret.getCause() == null) {
+            ret.initCause(e);
+        }
+        return ret;
+    }
+
+    /**
+     * Installs {@link RMISecurityManager} if it is not already installed.
+     *
+     * @throws  NoPermissionException
+     *          If security manager other than {@link RMISecurityManager}
+     *          is installed and prohibits installing a new security manager.
+     */
+    protected void installSecurityManager() throws NoPermissionException {
+        if (! (System.getSecurityManager() instanceof RMISecurityManager)) {
+            try {
+                System.setSecurityManager(new RMISecurityManager());
+            } catch (SecurityException e) {
+                throw (NoPermissionException) new NoPermissionException(
+                        "Cannot install RMISecurityManager").initCause(e);
+            }
+        }
+    }
+
+    /**
+     * Creates reference to the {@linkplain Registry RMI registry}
+     * located on the specified host and port.
+     *
+     * @param   host
+     *          Host. If <code>null</code>, localhost is assumed.
+     *          May not be <code>null</code>
+     *          if <code>csf</code> is not <code>null</code>.
+     *
+     * @param   port
+     *          Port. If <code>0</code>, default registry port
+     *          (<code>1099</code>) is assumed.
+     *          May not be <code>0</code>
+     *          if <code>csf</code> is not <code>null</code>.
+     *
+     * @param   csf
+     *          Client-side socket factory used to make connections to the
+     *          registry. If <code>null</code>, default socket factory is used.
+     *          See
+     *          {@link LocateRegistry#getRegistry(String, int, RMIClientSocketFactory)}.
+     *
+     * @return  Registry reference.
+     *
+     * @throws  NamingException
+     *          If getting registry failed.
+     */
+    protected Registry getRegistry(String host, int port,
+            RMIClientSocketFactory csf) throws NamingException {
+        try {
+            return ((csf != null) ? LocateRegistry.getRegistry(host, port, csf)
+                    : ((host != null)
+                        ? ((port != 0) ? LocateRegistry.getRegistry(host, port)
+                                       : LocateRegistry.getRegistry(host))
+                        : ((port != 0) ? LocateRegistry.getRegistry(port)
+                                       : LocateRegistry.getRegistry())));
+        } catch (RemoteException e) {
+            throw (NamingException) new NamingException().initCause(e);
+        }
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContextFactory.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContextFactory.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContextFactory.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RegistryContextFactory.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.3 $
+ */
+package org.apache.harmony.jndi.provider.rmi.registry;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.naming.ConfigurationException;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NotContextException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.ObjectFactory;
+
+import org.apache.harmony.jndi.provider.rmi.rmiURLContextFactory;
+
+
+/**
+ * Initial context and object factory for {@link RegistryContext}.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.3 $
+ */
+public class RegistryContextFactory
+        implements InitialContextFactory, ObjectFactory {
+
+    /**
+     * Default constructor.
+     */
+    public RegistryContextFactory() {}
+
+    /**
+     * {@inheritDoc}
+     */
+    public Context getInitialContext(Hashtable environment)
+            throws NamingException {
+        String url = null;
+
+        if (environment != null) {
+            url = (String) environment.get(Context.PROVIDER_URL);
+        }
+
+        if (url == null) {
+            url = RegistryContext.RMI_URL_PREFIX;
+        }
+
+        Object obj = new rmiURLContextFactory().getObjectInstance(
+                url, null, null, environment);
+
+        if (obj instanceof Context) {
+            return (Context) obj;
+        } else {
+            throw new NotContextException("Object instantiated using the "
+                    + "URL specified in environment is not a context: " + url);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+            Hashtable environment) throws Exception {
+        if (!(obj instanceof Reference)) {
+            return null;
+        }
+        Reference reference = (Reference) obj;
+
+        if (!reference.getFactoryClassName()
+                        .equals(RegistryContextFactory.class.getName())) {
+            return null;
+        }
+        int size = reference.size();
+
+        if (size < 1) {
+            throw new ConfigurationException("Reference is empty");
+        }
+        Vector urls = new Vector(size);
+
+        for (Enumeration e = reference.getAll(); e.hasMoreElements(); ) {
+            RefAddr refAddr = (RefAddr) e.nextElement();
+
+            if ((refAddr instanceof StringRefAddr)
+                    && refAddr.getType().equals(RegistryContext.ADDRESS_TYPE)) {
+                urls.add(refAddr.getContent());
+            }
+        }
+        size = urls.size();
+
+        if (size < 1) {
+            throw new ConfigurationException(
+                    "Reference contains no valid addresses");
+        }
+        Object ret = new rmiURLContextFactory().getObjectInstance(
+                urls.toArray(new String[size]), name, nameCtx, environment);
+
+        if (ret instanceof RegistryContext) {
+            ((RegistryContext) ret).setReference(reference);
+        }
+        return ret;
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReference.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReference.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReference.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReference.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ */
+package org.apache.harmony.jndi.provider.rmi.registry;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+
+
+/**
+ * This interface provides access to a remote reference.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ */
+public interface RemoteReference extends Remote {
+
+    /**
+     * Returns the remote reference.
+     *
+     * @return  Remote reference.
+     *
+     * @throws  NamingException
+     *          If naming exception occurs.
+     *
+     * @throws  RemoteException
+     *          If RMI remote exception occurs.
+     */
+    public Reference getReference() throws NamingException, RemoteException;
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ */
+package org.apache.harmony.jndi.provider.rmi.registry;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import java.rmi.server.UnicastRemoteObject;
+
+import javax.naming.Reference;
+
+
+/**
+ * This class stores a {@link Reference}
+ * and provides {@link Remote} access to it.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ */
+public class RemoteReferenceWrapper extends UnicastRemoteObject
+        implements RemoteReference {
+
+    /**
+     * serialVersionUID
+     */
+    private static final long serialVersionUID = -4565312021092681908L;
+
+    /**
+     * Wrapped reference.
+     */
+    protected Reference reference;
+
+    /**
+     * Creates wrapper for the specified reference.
+     *
+     * @param   reference
+     *          Reference to wrap.
+     *
+     * @throws  RemoteException
+     *          If object export failed.
+     */
+    public RemoteReferenceWrapper(Reference reference) throws RemoteException {
+        this.reference = reference;
+    }
+
+    /**
+     * Returns the wrapped reference.
+     *
+     * @return  Wrapped reference.
+     */
+    public Reference getReference() {
+        return reference;
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Skel.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Skel.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Skel.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Skel.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,64 @@
+/*
+ * RMI skeleton class
+ * for class org.apache.harmony.jndi.provider.rmi.registry.RemoteReferenceWrapper
+ * Compatible with stub protocol version 1.1/1.2
+ *
+ * Generated by DRL RMI Compiler (rmic).
+ *
+ * DO NOT EDIT!!!
+ * Contents subject to change without notice!
+ */
+package org.apache.harmony.jndi.provider.rmi.registry;
+
+
+public final class RemoteReferenceWrapper_Skel implements java.rmi.server.Skeleton {
+
+    private static final long interfaceHash = 2534274963554139942L;
+
+    private static final java.rmi.server.Operation[] operations = {
+        new java.rmi.server.Operation("javax.naming.Reference getReference()")
+    };
+
+    public java.rmi.server.Operation[] getOperations() {
+        return (java.rmi.server.Operation[]) operations.clone();
+    }
+
+    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {
+        if (opnum < 0) {
+            if (hash == 3529874867989176284L) {
+                opnum = 0;
+            } else {
+                throw new java.rmi.UnmarshalException("Invalid method hash: " + hash);
+            }
+        } else {
+            if (hash != interfaceHash) {
+                throw new java.rmi.server.SkeletonMismatchException(
+                        "Interface hash mismatch, expected: " + interfaceHash + ", received: " + hash);
+            }
+        }
+
+        org.apache.harmony.jndi.provider.rmi.registry.RemoteReferenceWrapper server = (org.apache.harmony.jndi.provider.rmi.registry.RemoteReferenceWrapper) obj;
+
+        switch (opnum) {
+
+        case 0: {    // getReference()
+
+            call.releaseInputStream();
+
+            javax.naming.Reference $result = server.getReference();
+
+            try {
+                java.io.ObjectOutput out = call.getResultStream(true);
+                out.writeObject($result);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("Error marshalling return", e);
+            }
+
+            break;
+        }
+
+        default:
+            throw new java.rmi.UnmarshalException("Invalid method number: " + opnum);
+        }
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Stub.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Stub.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Stub.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/RemoteReferenceWrapper_Stub.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,86 @@
+/*
+ * RMI stub class
+ * for class org.apache.harmony.jndi.provider.rmi.registry.RemoteReferenceWrapper
+ * Compatible with stub protocol version 1.1/1.2
+ *
+ * Generated by DRL RMI Compiler (rmic).
+ *
+ * DO NOT EDIT!!!
+ * Contents subject to change without notice!
+ */
+package org.apache.harmony.jndi.provider.rmi.registry;
+
+
+public final class RemoteReferenceWrapper_Stub extends java.rmi.server.RemoteStub
+        implements org.apache.harmony.jndi.provider.rmi.registry.RemoteReference, java.rmi.Remote {
+
+    private static final long serialVersionUID = 2;
+
+    private static final long interfaceHash = 2534274963554139942L;
+
+    private static boolean useNewInvoke;
+
+    private static final java.rmi.server.Operation[] operations = {
+        new java.rmi.server.Operation("javax.naming.Reference getReference()")
+    };
+
+    private static java.lang.reflect.Method $method_getReference_0;
+
+    static {
+        try {
+            java.rmi.server.RemoteRef.class.getMethod("invoke", new java.lang.Class[] {java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class});
+
+            $method_getReference_0 = org.apache.harmony.jndi.provider.rmi.registry.RemoteReference.class.getMethod("getReference", new java.lang.Class[] {});
+
+            useNewInvoke = true;
+        } catch (java.lang.NoSuchMethodException e) {
+            useNewInvoke = false;
+        }
+    }
+
+    public RemoteReferenceWrapper_Stub() {
+        super();
+    }
+
+    public RemoteReferenceWrapper_Stub(java.rmi.server.RemoteRef ref) {
+        super(ref);
+    }
+
+    // Implementation of getReference()
+    public javax.naming.Reference getReference()
+            throws javax.naming.NamingException, java.rmi.RemoteException {
+        try {
+            if (useNewInvoke) {
+                java.lang.Object $result = ref.invoke(this, $method_getReference_0, null, 3529874867989176284L);
+                return ((javax.naming.Reference) $result);
+            } else {
+                java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+
+                ref.invoke(call);
+
+                javax.naming.Reference $result;
+
+                try {
+                    java.io.ObjectInput in = call.getInputStream();
+                    $result = (javax.naming.Reference) in.readObject();
+                } catch (java.io.IOException e) {
+                    throw new java.rmi.UnmarshalException("Error unmarshalling return value", e);
+                } catch (java.lang.ClassNotFoundException e) {
+                    throw new java.rmi.UnmarshalException("Error unmarshalling return value", e);
+                } finally {
+                    ref.done(call);
+                }
+
+                return $result;
+            }
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (javax.naming.NamingException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("Undeclared checked exception", e);
+        }
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/package.html
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/package.html?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/package.html (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/registry/package.html Tue Aug 22 08:06:06 2006
@@ -0,0 +1,25 @@
+<html>
+<!--
+Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!--
+Author:  Vasily Zakharov
+Version: $Revision: 1.1.2.2 $
+-->
+<body>
+RMI Registry Service Provider for JNDI.
+</body>
+</html>

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContext.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContext.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContext.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContext.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.3 $
+ */
+package org.apache.harmony.jndi.provider.rmi;
+
+import java.util.Hashtable;
+
+import javax.naming.CompositeName;
+import javax.naming.NamingException;
+
+import javax.naming.spi.ResolveResult;
+
+import org.apache.harmony.jndi.provider.GenericURLContext;
+
+import org.apache.harmony.jndi.provider.rmi.registry.RegistryContext;
+
+
+/**
+ * RMI URL context implementation.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.3 $
+ */
+public class rmiURLContext extends GenericURLContext {
+
+    /**
+     * Creates instance of this context with empty environment.
+     */
+    public rmiURLContext() {
+        super(null);
+    }
+
+    /**
+     * Creates instance of this context with specified environment.
+     *
+     * @param   environment
+     *          Environment to copy.
+     */
+    public rmiURLContext(Hashtable environment) {
+        super(environment);
+    }
+
+    /**
+     * Determines the proper {@link RegistryContext} from the specified URL
+     * and returns the {@link ResolveResult} object with that context
+     * as resolved object and the rest of the URL as remaining name.
+     *
+     * @param   url
+     *          URL.
+     *
+     * @param   environment
+     *          Environment.
+     *
+     * @return  {@link ResolveResult} object with resolved context
+     *          as resolved object the rest of the URL as remaining name.
+     *
+     * @throws  NamingException
+     *          If some naming error occurs.
+     */
+    protected ResolveResult getRootURLContext(
+            String url, Hashtable environment) throws NamingException {
+        if (!url.startsWith(RegistryContext.RMI_URL_PREFIX)) {
+            throw new IllegalArgumentException(
+                    "Not an RMI URL, incorrect prefix: " + url);
+        }
+        int length = url.length();
+        int start = RegistryContext.RMI_URL_PREFIX.length();
+        String hostName = null;
+        int port = 0;
+
+        if ((start < length) && (url.charAt(start) == '/')) {
+            start++;
+
+            if ((start < length) && (url.charAt(start) == '/')) {
+                start++;
+
+                // end marks either first slash or end of URL.
+                int end = url.indexOf('/', start);
+                if (end < 0) {
+                    end = length;
+                }
+
+                // hostEnd marks either end of hostname or end of URL.
+                int hostEnd = url.indexOf(':', start);
+                if ((hostEnd < 0) || (hostEnd > end)) {
+                    hostEnd = end;
+                }
+
+                // Extracting host name.
+                if (start < hostEnd) {
+                    hostName = url.substring(start, hostEnd);
+                }
+
+                // Extracting port number.
+                int portStart = hostEnd + 1;
+                if (portStart < end) {
+                    try {
+                        port = Integer.parseInt(url.substring(portStart, end));
+                    } catch (NumberFormatException e) {
+                        throw (IllegalArgumentException)
+                                new IllegalArgumentException("Invalid port "
+                                    + "number in URL: " + url).initCause(e);
+                    }
+                }
+
+                // Point start to suffix string.
+                start = ((end < length) ? (end + 1) : length);
+            }
+        }
+
+        // Create remaining name.
+        CompositeName name = new CompositeName();
+        if (start < length) {
+            name.add(url.substring(start));
+        }
+
+        return new ResolveResult(
+                new RegistryContext(hostName, port, environment), name);
+    }
+}

Added: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContextFactory.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContextFactory.java?rev=433660&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContextFactory.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/org/apache/harmony/jndi/provider/rmi/rmiURLContextFactory.java Tue Aug 22 08:06:06 2006
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ */
+package org.apache.harmony.jndi.provider.rmi;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+
+import org.apache.harmony.jndi.provider.GenericURLContextFactory;
+
+
+/**
+ * URL context factory for {@link rmiURLContext}.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ */
+public class rmiURLContextFactory extends GenericURLContextFactory {
+
+    /**
+     * Default constructor.
+     */
+    public rmiURLContextFactory() {}
+
+    /**
+     * Returns new {@link rmiURLContext}. Used by
+     * {@link GenericURLContextFactory#getObjectInstance(Object, Name, Context, Hashtable)}.
+     *
+     * @param   environment
+     *          Environment.
+     *
+     * @return  New {@link rmiURLContext}.
+     */
+    protected Context createURLContext(Hashtable environment) {
+        return new rmiURLContext(environment);
+    }
+}