You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by te...@apache.org on 2006/05/31 23:26:36 UTC

svn commit: r410674 - /incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java

Author: tellison
Date: Wed May 31 14:26:36 2006
New Revision: 410674

URL: http://svn.apache.org/viewvc?rev=410674&view=rev
Log:
Further generics uplift and code formatting.

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java?rev=410674&r1=410673&r2=410674&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java Wed May 31 14:26:36 2006
@@ -1,4 +1,4 @@
-/* Copyright 2004 The Apache Software Foundation or its licensors, as applicable
+/* Copyright 2004, 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.
@@ -11,821 +11,803 @@
  * 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.
- */
-
-
-package javax.naming.spi;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.StringTokenizer;
-
-import javax.naming.CannotProceedException;
-import javax.naming.Context;
-import org.apache.harmony.jndi.internal.EnvironmentReader;
-import org.apache.harmony.jndi.internal.UrlParser;
-
-import javax.naming.Name;
-import javax.naming.NamingException;
-import javax.naming.NoInitialContextException;
-import javax.naming.RefAddr;
-import javax.naming.Reference;
-import javax.naming.Referenceable;
-import javax.naming.StringRefAddr;
-
-/**
- * The <code>NamingManager</code> class should not be instantiated although 
- * it can be extended by classes within the <code>javax.naming.spi</code> 
- * package - see {@link DirectoryManager}. All its methods are static.
- * <p>
- * The methods are used by service providers for accessing object and state
- * factories and for determining continuation contexts. Many of the methods
- * create objects. These may be <code>Context</code> objects or objects 
- * referred to by the naming service.</p>
- * <p>
- * The <code>Name</code> and <code>Hashtable</code> arguments passed to the 
- * <code>NamingManager</code> methods remain owned purely by the calling 
- * method. They must not be changed or referenced.</p>
- * <p>
- * It should be noted that it is possible for an application to access a
- * namespace other than that supplied by the default <code>InitialContext</code>
- * (as specified by <code>Context.INITIAL_CONTEXT_FACTORY</code>). It is 
- * possible to call the following <code>InitialContext</code> methods passing a
- * URL string either as the <code>String</code> or <code>Name</code> parameter: 
- * <code>lookup, bin, rebind, unbind, rename, list, listBindings, 
- * destroySubcontext, createSubcontext, lookupLink, getNameParser</code>. This 
- * allows you to have one <code>InitialContext</code> object where these 
- * methods usually use the default initial context but access a URL 
- * <code>Context</code> instead when invoked with a URL string.</p>
- * <p>
- * A URL string is of the format abc:\nnnnnn where abc is the scheme of the 
- * URL. (See <code>InitialContext</code> where it refers to RFC1738.)
- * When a URL string is supplied to those <code>InitialContext</code> methods,
- * a URL context is used instead of the default initial context when 
- * performing that method. URL context factories are used to create URL 
- * contexts. A URL context factory is really just a service provider's 
- * implementation of an <code>ObjectFactory</code>. It is not essential that a 
- * service provider supplies one if they do not wish to support URL 
- * <code>Contexts.</code></p>
- * <p>
- * See the <code>getURLContext</code> method for a description of how a URL 
- * context factory is located.</p>
- * <p>
- * Please note that multithreaded access to this class must be safe.
- * For example, for thread safety, it should not be possible for one thread
- * to read the installed <code>InitialContextFactoryBuilder</code> or 
- * <code>ObjectFactoryBuilder</code> while another thread is in the process 
- * of setting it.</p>
- * <p>
- * Also note that privileges should be granted to get the context classloader
- * and to read the resource files.</p>
- * 
- * @see DirectoryManager
- */
-
-public class NamingManager {
-
-    /*
-     * -------------------------------------------------------------------
-     * Constants
-     * -------------------------------------------------------------------
-     */
-
-    /** 
-     * The property name of <code>CannotProceedException</code> in a 
-     * context's environment.
-     */
-    public static final String CPE = "java.naming.spi.CannotProceedException"; //$NON-NLS-1$
-
-    /*
-     * -------------------------------------------------------------------
-     * Class variables
-     * -------------------------------------------------------------------
-     */
-
-    static InitialContextFactoryBuilder icfb = null;
-    static ObjectFactoryBuilder ofb = null;
-    
-    /*
-     * -------------------------------------------------------------------
-     * Constructors
-     * -------------------------------------------------------------------
-     */
-    NamingManager(){
-        //package private to prevent it being instanced but make it can be subclassed by DirectoryManager
-    }
-
-    /*
-     * -------------------------------------------------------------------
-     * Methods
-     * -------------------------------------------------------------------
-     */
-
-    /**
-     * Install an <code>InitialContextFactoryBuilder</code>. Once this has 
-     * been set it cannot be reset. Attempts to do so cause an 
-     * <code>IllegalStateException</code>. The builder can only be installed 
-     * if the security policy allows the setting of the factory.
-     *
-     * @param icfb  the builder to be installed - can be null,
-     *              but then no builder is installed.
-     * @throws IllegalStateException if an builder has already
-     *              been installed.
-     * @throws SecurityException is a security error prevents the installation.
-     * @throws NamingException for other errors encountered.
-     */
-    public static synchronized void setInitialContextFactoryBuilder(InitialContextFactoryBuilder icfb)
-        throws IllegalStateException, SecurityException, NamingException {
-
-        if (null != NamingManager.icfb) {
-            throw new IllegalStateException("InitialContextFactoryBuilder cannot be reset"); //$NON-NLS-1$
-        }
-
-        // check security access
-        SecurityManager sm = System.getSecurityManager();
-        if (null != sm) {
-            sm.checkSetFactory();
-        }
-
-        NamingManager.icfb = icfb;
-    }
-
-    /**
-     * Returns true when an <code>InitialContextFactoryBuilder</code> has 
-     * been installed.
-     * 
-     * @return true when an <code>InitialContextFactoryBuilder</code> has 
-     * been installed.
-     */
-    public static boolean hasInitialContextFactoryBuilder() {
-        return null != icfb;
-    }
-
-    /**
-     * Install an <code>ObjectFactoryBuilder</code>. Once this has been set 
-     * it cannot be reset. Attempts to do so cause an 
-     * <code>IllegalStateException</code>. The builder can only be installed 
-     * if the security policy allows the setting of the factory.
-     *
-     * @param ofb   the <code>ObjectFactoryBuilder</code> to be installed 
-     *              - can be null, but then no builder is installed.
-     * @throws IllegalStateException if an <code>ObjectFactoryBuilder</code> 
-     *         has already been installed.
-     * @throws SecurityException is a security error prevents the installation.
-     * @throws NamingException for other errors encountered.
-     */
-    public static synchronized void setObjectFactoryBuilder(ObjectFactoryBuilder ofb)
-        throws IllegalStateException, SecurityException, NamingException {
-
-        if (null != NamingManager.ofb) {
-            throw new IllegalStateException("ObjectFactoryBuilder cannot be reset"); //$NON-NLS-1$
-        }
-
-        // check security access
-        SecurityManager sm = System.getSecurityManager();
-        if (null != sm) {
-            sm.checkSetFactory();
-        }
-
-        NamingManager.ofb = ofb;
-    }
-
-    /**
-     * Create an <code>InitialContext</code> from either a previously 
-     * installed <code>InitialContextFactoryBuilder</code> or from the 
-     * <code>Context.INITIAL_CONTEXT_FACTORY</code> property in the supplied 
-     * <code> Hashtable h</code> if no builder is installed.
-     * An installed <code>InitialContextFactoryBuilder</code> can generate 
-     * a factory which can be used to create the <code>InitialContext</code>.
-     * The <code>Context.INITIAL_CONTEXT_FACTORY</code> property contains the 
-     * class of a factory which can be used to create the 
-     * <code>InitialContext</code>.
-     * 
-     * @param h a hashtable containing properties and values - may be null
-     * @return  an <code>InitialContext</code>
-     * @throws NoInitialContextException if the <code>InitialContext</code> 
-     *         cannot be created.
-     * @throws NamingException
-     */
-    public static Context getInitialContext(Hashtable h)
-        throws NoInitialContextException, NamingException {
-
-        // if InitialContextFactoryBuilder is set
-        if (null != icfb) {
-            // create InitialContext using builder
-            return icfb.createInitialContextFactory(h).getInitialContext(h);
-        }
-
-        // create InitialContext using factory specified in hashtable
-        try {
-            // get factory class name
-            String factoryClassName =
-                (String) h.get(Context.INITIAL_CONTEXT_FACTORY);
-            // new factory instance
-            Class factoryClass = classForName(factoryClassName);
-            InitialContextFactory factory =
-                (InitialContextFactory) factoryClass.newInstance();
-            // create initial context instance using the factory
-            return factory.getInitialContext(h);
-        } catch (NamingException e) {
-            // throw NamingException
-            throw e;
-        } catch (Exception e) {
-            // failed, throw NoInitialContextException
-            NamingException nex =
-                new NoInitialContextException(
-                    "Failed to create InitialContext using factory specified in hashtable " //$NON-NLS-1$
-                        + h);
-            nex.setRootCause(e);
-            throw nex;
-        }
-    }
-
-    /**
-     * Create an object from either a previously installed 
-     * <code>ObjectFactoryBuilder</code> or from a supplied reference or 
-     * from the <code>Context.OBJECT_FACTORIES</code> property in the supplied 
-     * <code>Hashtable h</code>.
-     * <p>
-     * An installed <code>ObjectFactoryBuilder</code> can generate a factory 
-     * which can be used to create the object instance to return to caller. 
-     * Any encountered exceptions are thrown.</p>
-     * <p>
-     * If an <code>ObjectFactoryBuilder</code> has not been installed then 
-     * the supplied <code>Object o</code> may provide a <code>Reference</code>
-     * or <code>Referenceable</code> object. If so, then that 
-     * <code>Object o</code> may have an associated class in a factory which 
-     * could be loaded and used to create the object instance. If the factory 
-     * class cannot be loaded then the <code>URLClassLoader</code> may be able 
-     * to load a class from the list of URLs specified in the reference's 
-     * factory class location. Any exceptions encountered are passed up.</p>
-     * <p>
-     * If a reference is supplied but no factory class can be loaded from it 
-     * then this method returns the supplied object <code>o</code>.</p>
-     * <p>
-     * If a factory class loads successfully and can then be used to create an 
-     * object instance then that instance is returned to the caller.</p>
-     * <p>
-     * If no factory name was associated with the <code>Reference</code> 
-     * object <code>o</code> then see whether the <code>Reference</code> or 
-     * <code>Referenceable</code> object has any <code>StringRefAddrs</code> 
-     * of address type URL or url in its address list. For each entry in the 
-     * list, in the order they appear in the list, it may be possible to use 
-     * the URL factory to create the object. A URL in a 
-     * <code>StringRefAddr</code> should have a scheme which can be used to 
-     * locate the associated URL context factory in the same way as in the 
-     * <code>getURLContext</code> method. (The scheme is the part which comes 
-     * before :\. For example the URL http://www.apache.org has the scheme http.) 
-     * A URL with no scheme would be ignored for these purposes.</p>
-     * <p>
-     * If no <code>ObjectFactoryBuilder</code> was installed, no factory 
-     * class name is supplied with a <code>Reference</code> and no URL contexts
-     * succeeded in creating an <code>Object</code> then try the factories in 
-     * <code>Context.OBJECT_FACTORIES</code> for this environment. Also try 
-     * the provider resource file belonging to the context <code>c</code>.
-     * (See <code>Context</code> description for details of Provider resource 
-     * files.) If any factory throws an exception then pass that back to the 
-     * caller - no further factories are tried.</p>
-     * <p>
-     * If all factories fail to load or create the <code>Object</code> then 
-     * return the argument object <code>o</code> as the returned object.</p>
-     *
-     * @param o an object which may provide reference or location information. 
-     *          May be null.
-     * @param n The name of the <code>Object</code> relative to the default 
-     *          initial context(or relative to the Context c if it is supplied)
-     * @param c the <code>Context</code> to which the <code>Name</code> is 
-     *          relative
-     * @param h a <code>Hashtable</code> containing environment properties and 
-     *          values - may be null
-     * @return  a new <code>Object</code> or the supplied <code>Object o</code>
-     *          if one cannot be created.
-     * @throws NamingException if one is encountered
-     * @throws Exception if any other exception is encountered
-     */
-    public static Object getObjectInstance(
-        Object o,
-        Name n,
-        Context c,
-        Hashtable h)
-        throws NamingException, Exception {
-
-        // 1. try ObjectFactoryBuilder, if it is set
-        if (null != ofb) {
-            // use the builder to create an object factory
-            ObjectFactory factory = ofb.createObjectFactory(o, h);
-            // get object instance using the factory and return
-            return factory.getObjectInstance(o, n, c, h);
-        }
-
-        // 2. see whether o is a Referenceable or a Reference
-        Reference ref = null;
-        if (o instanceof Referenceable) {
-            ref = ((Referenceable) o).getReference();
-        }
-        if (o instanceof Reference) {
-            ref = (Reference) o;
-        }
-        // if o is a Referenceable or a Reference
-        if (null != ref) {
-            // if a factory class name is supplied by the reference, use it to create
-            if (null != ref.getFactoryClassName()) {
-                return getObjectInstanceByFactoryInReference(ref, o, n, c, h);
-            }
-            // see if ref has any StringRefAddrs of address type URL, 
-            Object result = getObjectInstanceByUrlRefAddr(n, c, h, ref);
-            // if success, return it
-            if (null != result) {
-                return result;
-            }
-        }
-
-        // 3. try Context.OBJECT_FACTORIES
-        Object result = getObjectInstanceByObjectFactory(o, n, c, h);
-        if (null != result) {
-            return result;
-        }
-
-        // all failed, just return o
-        return o;
-    }
-
-    private static Object getObjectInstanceByObjectFactory(
-        Object o,
-        Name n,
-        Context c,
-        Hashtable h)
-        throws NamingException, Exception {
-        // obtain object factories from hashtable and service provider resource file
-        String fnames[] =
-            EnvironmentReader
-                .getFactoryNamesFromEnvironmentAndProviderResource(
-                h,
-                c,
-                Context.OBJECT_FACTORIES);
-        // for each object factory
-        for (int i = 0; i < fnames.length; i++) {
-            // new factory instance by its class name
-            ObjectFactory factory = null;
-            try {
-                factory = (ObjectFactory) classForName(fnames[i]).newInstance();
-            } catch (Exception e) {
-                continue;
-            }
-            // create object using factory
-            Object obj = factory.getObjectInstance(o, n, c, h);
-            if (null != obj) {
-                return obj;
-            }
-        }
-        // no object factory succeeded, return null
-        return null;
-    }
-
-    private static Object getObjectInstanceByUrlRefAddr(
-        Name n,
-        Context c,
-        Hashtable h,
-        Reference ref)
-        throws NamingException {
-        // obtain pkg prefixes from hashtable and service provider resource file
-        String pkgPrefixes[] =
-            EnvironmentReader
-                .getFactoryNamesFromEnvironmentAndProviderResource(
-                h,
-                c,
-                Context.URL_PKG_PREFIXES);
-        // for each RefAddr
-        Enumeration enumeration = ref.getAll();
-        while (enumeration.hasMoreElements()) {
-            RefAddr addr = (RefAddr) enumeration.nextElement();
-            // if it is StringRefAddr and type is URL
-            if (addr instanceof StringRefAddr
-                && addr.getType().equalsIgnoreCase("URL")) { //$NON-NLS-1$
-                // get the url address
-                String url = (String) ((StringRefAddr) addr).getContent();
-                // try create using url context factory
-                Object obj =
-                    getObjectInstanceByUrlContextFactory(
-                        url,
-                        n,
-                        c,
-                        h,
-                        pkgPrefixes,
-                        UrlParser.getScheme(url));
-                // if success, return the created obj
-                if (null != obj) {
-                    return obj;
-                }
-            }
-        }
-        // failed to create using any StringRefAddr of address type URL, return null
-        return null;
-    }
-
-    private static Object getObjectInstanceByUrlContextFactory(
-        String url,
-        Name n,
-        Context c,
-        Hashtable h,
-        String pkgPrefixes[],
-        String schema)
-        throws NamingException {
-        // if schema is empty or null, fail, return null
-        if (null == schema || 0 == schema.length()) {
-            return null;
-        }
-
-        // for each pkg prefix
-        for (int i = 0; i < pkgPrefixes.length; i++) {
-            ObjectFactory factory = null;
-            try {
-                // create url context factory instance
-                String clsName =
-                    pkgPrefixes[i]
-                        + "." //$NON-NLS-1$
-                        + schema
-                        + "." //$NON-NLS-1$
-                        + schema
-                        + "URLContextFactory"; //$NON-NLS-1$
-                factory = (ObjectFactory) classForName(clsName).newInstance();
-            } catch (Exception e) {
-                // failed to create factory, continue trying
-                continue;
-            }
-            try {
-                // create obj using url context factory
-                Object obj = factory.getObjectInstance(url, n, c, h);
-                // if create success, return it
-                if (null != obj) {
-                    return obj;
-                }
-            } catch (Exception e) {
-                // throw NamingException, if factory fails
-                if (e instanceof NamingException) {
-                    throw (NamingException) e;
-                }
-                NamingException nex =
-                    new NamingException("Failed to create object instance"); //$NON-NLS-1$
-                nex.setRootCause(e);
-                throw nex;
-            }
-        }
-        // fail to create using url context factory, return null
-        return null;
-    }
-
-    private static Object getObjectInstanceByFactoryInReference(
-        Reference ref,
-        Object o,
-        Name n,
-        Context c,
-        Hashtable h)
-        throws Exception {
-        ObjectFactory factory = null;
-
-        // try load the factory by its class name
-        try {
-            factory =
-                (ObjectFactory) classForName(ref.getFactoryClassName())
-                    .newInstance();
-        } catch (ClassNotFoundException e) {
-        	// Ignore.
-        }
-
-        // try load the factory from its class location
-        if (null == factory && null != ref.getFactoryClassLocation()) {
-            factory =
-                (ObjectFactory) loadFactoryFromLocation(ref
-                    .getFactoryClassName(),
-                    ref.getFactoryClassLocation());
-        }
-        // if factory cannot be loaded
-        if (null == factory) {
-            // return o
-            return o;
-        }
-
-        // get object instance using the factory and return it
-        return factory.getObjectInstance(ref, n, c, h);
-    }
-
-    /*
-     * If cannot load class, return null.
-     * Throws any exceptions except ClassNotFoundException
-     */
-    private static Object loadFactoryFromLocation(
-        String clsName,
-        String location)
-        throws Exception {
-
-        // convert location into an array of URL, separated by ' '
-        StringTokenizer st = new StringTokenizer(location, " "); //$NON-NLS-1$
-        URL urls[] = new URL[st.countTokens()];
-        for (int i = 0; i < urls.length; i++) {
-            urls[i] = new URL(st.nextToken());
-        }
-
-        // new a URLClassLoader from the URLs
-        URLClassLoader l = new URLClassLoader(urls);
-
-        // try load factory by URLClassLoader
-        try {
-            // return the new instance
-            return l.loadClass(clsName).newInstance();
-        } catch (ClassNotFoundException e) {
-            // return null if class loading failed
-            return null;
-        }
-    }
-
-    /**
-     * Get the state of an Object.
-     * <p>
-     * The <code>Context.STATE_FACTORIES</code> property from the 
-     * <code>Hashtable h</code> together with the 
-     * <code>Context.STATE_FACTORIES</code> property from the provider resource
-     * file of the <code>Context c</code> provides the list of factories tried 
-     * to get an object's state.</p>
-     * <p>
-     * Each factory in the list is attempted to be loaded using the context 
-     * class loader. Once a class is loaded then it can be used to create a 
-     * new instance of it to obtain the factory which can then use its 
-     * <code>getStateToBind</code> to find the return object. Once an object 
-     * is found then it is not necessary to examine further factories and the 
-     * object is returned it as the return parameter.</p>
-     * <p>
-     * If no factory is loaded or all loaded factories fail to return an object
-     * then return the supplied <code>Object o</code> as the return param.</p>
-     * <p>
-     * Note for service provider implementors:
-     * Classes which implement the <code>StateFactory</code> interface must be 
-     * public with a public constructor that has no parameters.</p>
-     *
-     * @param o an object which may provide reference or location information. 
-     *          May be null.
-     * @param n the name of the <code>Object</code> relative to the default 
-     *          initial context (or relative to the Context c if it is supplied)
-     * @param c the <code>Context</code> to which the <code>Name</code> is 
-     *          relative
-     * @param h a <code>Hashtable</code> containing environment properties and 
-     *          values - may be null
-     * @return  the state of the specified object
-     * @throws NamingException if one is encountered
-     */
-    public static Object getStateToBind(
-        Object o,
-        Name n,
-        Context c,
-        Hashtable h)
-        throws NamingException {
-
-        // obtain state factories from hashtable and service provider resource file
-        String fnames[] =
-            EnvironmentReader
-                .getFactoryNamesFromEnvironmentAndProviderResource(
-                h,
-                c,
-                Context.STATE_FACTORIES);
-
-        // for each state factory
-        for (int i = 0; i < fnames.length; i++) {
-            // new factory instance by its class name
-            StateFactory factory = null;
-            try {
-                factory = (StateFactory) classForName(fnames[i]).newInstance();
-            } catch (Exception e) {
-                continue;
-            }
-            // try obtain state using the factory
-            Object state = factory.getStateToBind(o, n, c, h);
-            // if a state obtained successfully, return it
-            if (null != state) {
-                return state;
-            }
-        }
-
-        // all factories failed, return the input argument o
-        return o;
-    }
-
-    /**
-     * Creates a URL <code>Context</code> which can subsequently be used to 
-     * resolve any URLs with the URL scheme s. A <code>URLContextFactory</code>
-     * is a type of <code>ObjectFactory</code> used to create a 
-     * <code>URLContext</code> when <code>getObjectInstance</code> is
-     * invoked with the <code>Object o</code> set to null 
-     * (see the description of <code>ObjectFactory</code>).
-     * <p>
-     * This <code>getURLContext</code> method tries to locate the 
-     * <code>URLContextFactory</code> based on the 
-     * <code>Context.URL_PKG_PREFIXES</code> property which contains the 
-     * prefixes to be tried as the start of the package name. (See 
-     * <code>Context</code>).</p>
-     * <p>
-     * Each package prefix entry (and finally the default value) are tried to
-     * find the class which can be used to create the Context.</p>
-     * <p>
-     * A full class name is derived as 
-     * <code>packageprefix.s.sURLContextFactory</code> where <code>s</code> 
-     * is the scheme.</p>
-     * <p>
-     * For example if a scheme is abc and the package prefix to try is com.ibm
-     * then the factory class to try is 
-     * <code>com.ibm.abc.abcURLContextFactory</code>. Once a factory is 
-     * created then a <code>Context</code> is created using the special use of 
-     * <code>ObjectFactory.getObjectInstance</code>.</p>
-     * <p>
-     * Once a first factory is created, it is used to create the context,
-     * and NO further attemptions will be made on other pkg prefixes.</p>
-     *
-     * @param schema    the URL scheme to which the Context will relate
-     * @param envmt     a <code>Hashtable</code> containing environment 
-     *                  properties and values - may be null
-     * @return          the URL <code>Context</code> or null if no 
-     *                  <code>URLContextFactory</code> instance 
-     *                  can be created and therefore a Context cannot be 
-     *                  created.
-     * @throws NamingException if one is encountered.
-     */
-    public static Context getURLContext(String schema, Hashtable envmt)
-        throws NamingException {
-
-        if (null == schema || 0 == schema.length() || null == envmt) {
-            return null;
-        }
-
-        // obtain pkg prefixes from hashtable
-        String pkgPrefixes[] =
-            EnvironmentReader
-                .getFactoryNamesFromEnvironmentAndProviderResource(
-                envmt,
-                null,
-                Context.URL_PKG_PREFIXES);
-
-        // for each pkg prefix
-        for (int i = 0; i < pkgPrefixes.length; i++) {
-            // create factory instance
-            ObjectFactory factory;
-            try {
-                String clsName =
-                    pkgPrefixes[i]
-                        + "." //$NON-NLS-1$
-                        + schema
-                        + "." //$NON-NLS-1$
-                        + schema
-                        + "URLContextFactory"; //$NON-NLS-1$
-                factory = (ObjectFactory) classForName(clsName).newInstance();
-            } catch (Exception ex) {
-                // fail to create factory, continue to try another
-                continue;
-            }
-            try {
-                // create url context using the factory, and return it
-                return (Context) factory.getObjectInstance(
-                    null,
-                    null,
-                    null,
-                    envmt);
-            } catch (NamingException e) {
-                // find NamingException, throw it
-                throw e;
-            } catch (Exception e) {
-                // other exception, throw as NamingException
-                NamingException nex =
-                    new NamingException(
-                        "other exception happens: " + e.toString()); //$NON-NLS-1$
-                nex.setRootCause(e);
-                throw nex;
-            }
-        }
-
-        // cannot create context instance from any pkg prefixes, return null
-        return null;
-    }
-
-    /**
-     * Create the next context when using federation. All the information
-     * required to do this is contained in the 
-     * <code>CannotProceedException</code> <code>e</code>.
-     * If the resolved object is null then throw the supplied 
-     * <code>CannotProceedException</code> <code>e</code> using the stack 
-     * details from this thread. The resolved object in <code>e</code> may
-     * already be a <code>Context</code>. This is the case  where the service 
-     * provider gives an explicit pointer to the next naming
-     * system.  A Context object is returned as the continuation context, but
-     * need not be the same object instance as the resolved object.
-     * <p>
-     * If the resolved object is not already a <code>Context</code> then it is 
-     * necessary to use the resolved object together with the 
-     * <code>altName</code> name, the <code>altNameCtx</code> context and the 
-     * environment hashtable to get an instance of the object. This should 
-     * then be a context which is returned as the continuation context. If 
-     * an instance cannot be obtained then throw the supplied 
-     * <code>CannotProceedException</code> using the stack details from this
-     * thread.</p>
-     * <p>
-     * This method is responsible for setting the property denoted by the 
-     * <code>CPE</code> string to be the supplied 
-     * <code>CannotProceedException</code> for 
-     * the exception <code>e</code> environment. The continuation context 
-     * should then inherit this property.</p>
-     *
-     * @param cpe   the <code>CannotProceedException</code> generated by the 
-     *              context of the previous naming system when it can proceed 
-     *              no further.
-     * @return      the next Context when using federation
-     * @throws NamingException if the resolved object is null or if a 
-     *              context cannot be obtained from it either directly or 
-     *              indirectly.
-     */
-    public static Context getContinuationContext(CannotProceedException cpe)
-        throws NamingException {
-
-        Context ctx = null;
-
-        // set CPE property of the env
-        if (cpe.getEnvironment() == null) {
-            cpe.setEnvironment(new Hashtable<String, CannotProceedException>());
-        }
-        ((Hashtable<String, CannotProceedException>)cpe.getEnvironment()).put(CPE, cpe);
-
-        // if resolved object is null
-        if (null == cpe.getResolvedObj()) {
-            // re-throw cpe
-            cpe.fillInStackTrace();
-            throw cpe;
-        }
-
-        // if cpe's resolved obj is Context
-        if (cpe.getResolvedObj() instanceof Context) {
-            // accept it as the continuation context
-            ctx = (Context) cpe.getResolvedObj();
-        } else {
-            // otherwise, call getObjectInstance() to get a context instance
-            try {
-                ctx =
-                    (Context) getObjectInstance(cpe.getResolvedObj(),
-                        cpe.getAltName(),
-                        cpe.getAltNameCtx(),
-                        cpe.getEnvironment());
-            } catch (Exception ex) {
-                // throw back CPE in case of any exception
-                throw cpe;
-            }
-            // if ctx cannot be obtained
-            if (null == ctx) {
-                // re-throw CPE
-                cpe.fillInStackTrace();
-                throw cpe;
-            }
-        }
-
-        // return the continuation context
-        return ctx;
-    }
-
-    private static Class classForName(final String className)
-        throws ClassNotFoundException {
-
-        Class cls = AccessController.doPrivileged(new PrivilegedAction<Class>() {
-            public Class run() {
-                    // try thread context class loader first
-    try {
-                    return Class.forName(
-                        className,
-                        true,
-                        Thread.currentThread().getContextClassLoader());
-                } catch (ClassNotFoundException e) {
-                	// Ignored.
-                }
-                // try system class loader second
-                try {
-                    return Class.forName(
-                        className,
-                        true,
-                        ClassLoader.getSystemClassLoader());
-                } catch (ClassNotFoundException e1) {
-                	// Ignored.
-                }
-                // return null, if fail to load class
-                return null;
-            }
-        });
-
-        if (cls == null) {
-            throw new ClassNotFoundException(
-                "class " + className + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
-        }
-
-        return cls;
-
-    }
-
-}
-
-
+ */
+
+package javax.naming.spi;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import javax.naming.CannotProceedException;
+import javax.naming.Context;
+import org.apache.harmony.jndi.internal.EnvironmentReader;
+import org.apache.harmony.jndi.internal.UrlParser;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+
+/**
+ * The <code>NamingManager</code> class should not be instantiated although it
+ * can be extended by classes within the <code>javax.naming.spi</code> package -
+ * see {@link DirectoryManager}. All its methods are static.
+ * <p>
+ * The methods are used by service providers for accessing object and state
+ * factories and for determining continuation contexts. Many of the methods
+ * create objects. These may be <code>Context</code> objects or objects
+ * referred to by the naming service.
+ * </p>
+ * <p>
+ * The <code>Name</code> and <code>Hashtable</code> arguments passed to the
+ * <code>NamingManager</code> methods remain owned purely by the calling
+ * method. They must not be changed or referenced.
+ * </p>
+ * <p>
+ * It should be noted that it is possible for an application to access a
+ * namespace other than that supplied by the default <code>InitialContext</code>
+ * (as specified by <code>Context.INITIAL_CONTEXT_FACTORY</code>). It is
+ * possible to call the following <code>InitialContext</code> methods passing
+ * a URL string either as the <code>String</code> or <code>Name</code>
+ * parameter: <code>lookup, bin, rebind, unbind, rename, list, listBindings, 
+ * destroySubcontext, createSubcontext, lookupLink, getNameParser</code>.
+ * This allows you to have one <code>InitialContext</code> object where these
+ * methods usually use the default initial context but access a URL
+ * <code>Context</code> instead when invoked with a URL string.
+ * </p>
+ * <p>
+ * A URL string is of the format abc:\nnnnnn where abc is the scheme of the URL.
+ * (See <code>InitialContext</code> where it refers to RFC1738.) When a URL
+ * string is supplied to those <code>InitialContext</code> methods, a URL
+ * context is used instead of the default initial context when performing that
+ * method. URL context factories are used to create URL contexts. A URL context
+ * factory is really just a service provider's implementation of an
+ * <code>ObjectFactory</code>. It is not essential that a service provider
+ * supplies one if they do not wish to support URL <code>Contexts.</code>
+ * </p>
+ * <p>
+ * See the <code>getURLContext</code> method for a description of how a URL
+ * context factory is located.
+ * </p>
+ * <p>
+ * Please note that multithreaded access to this class must be safe. For
+ * example, for thread safety, it should not be possible for one thread to read
+ * the installed <code>InitialContextFactoryBuilder</code> or
+ * <code>ObjectFactoryBuilder</code> while another thread is in the process of
+ * setting it.
+ * </p>
+ * <p>
+ * Also note that privileges should be granted to get the context classloader
+ * and to read the resource files.
+ * </p>
+ * 
+ * @see DirectoryManager
+ */
+
+public class NamingManager {
+
+    /*
+     * -------------------------------------------------------------------
+     * Constants
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * The property name of <code>CannotProceedException</code> in a context's
+     * environment.
+     */
+    public static final String CPE = "java.naming.spi.CannotProceedException"; //$NON-NLS-1$
+
+    /*
+     * ------------------------------------------------------------------- 
+     * Class variables
+     * -------------------------------------------------------------------
+     */
+
+    static InitialContextFactoryBuilder icfb = null;
+
+    static ObjectFactoryBuilder ofb = null;
+
+    /*
+     * -------------------------------------------------------------------
+     * Constructors
+     * -------------------------------------------------------------------
+     */
+    NamingManager() {
+        // package private to prevent it being instanced but make it can be
+        // subclassed by DirectoryManager
+    }
+
+    /*
+     * -------------------------------------------------------------------
+     * Methods
+     * -------------------------------------------------------------------
+     */
+
+    /**
+     * Install an <code>InitialContextFactoryBuilder</code>. Once this has
+     * been set it cannot be reset. Attempts to do so cause an
+     * <code>IllegalStateException</code>. The builder can only be installed
+     * if the security policy allows the setting of the factory.
+     * 
+     * @param icfb
+     *            the builder to be installed - can be null, but then no builder
+     *            is installed.
+     * @throws IllegalStateException
+     *             if an builder has already been installed.
+     * @throws SecurityException
+     *             is a security error prevents the installation.
+     * @throws NamingException
+     *             for other errors encountered.
+     */
+    public static synchronized void setInitialContextFactoryBuilder(
+            InitialContextFactoryBuilder icfb) throws IllegalStateException,
+            SecurityException, NamingException {
+
+        if (null != NamingManager.icfb) {
+            throw new IllegalStateException(
+                    "InitialContextFactoryBuilder cannot be reset"); //$NON-NLS-1$
+        }
+
+        // check security access
+        SecurityManager sm = System.getSecurityManager();
+        if (null != sm) {
+            sm.checkSetFactory();
+        }
+
+        NamingManager.icfb = icfb;
+    }
+
+    /**
+     * Returns true when an <code>InitialContextFactoryBuilder</code> has been
+     * installed.
+     * 
+     * @return true when an <code>InitialContextFactoryBuilder</code> has been
+     *         installed.
+     */
+    public static boolean hasInitialContextFactoryBuilder() {
+        return null != icfb;
+    }
+
+    /**
+     * Install an <code>ObjectFactoryBuilder</code>. Once this has been set
+     * it cannot be reset. Attempts to do so cause an
+     * <code>IllegalStateException</code>. The builder can only be installed
+     * if the security policy allows the setting of the factory.
+     * 
+     * @param ofb
+     *            the <code>ObjectFactoryBuilder</code> to be installed - can
+     *            be null, but then no builder is installed.
+     * @throws IllegalStateException
+     *             if an <code>ObjectFactoryBuilder</code> has already been
+     *             installed.
+     * @throws SecurityException
+     *             is a security error prevents the installation.
+     * @throws NamingException
+     *             for other errors encountered.
+     */
+    public static synchronized void setObjectFactoryBuilder(
+            ObjectFactoryBuilder ofb) throws IllegalStateException,
+            SecurityException, NamingException {
+
+        if (null != NamingManager.ofb) {
+            throw new IllegalStateException(
+                    "ObjectFactoryBuilder cannot be reset"); //$NON-NLS-1$
+        }
+
+        // check security access
+        SecurityManager sm = System.getSecurityManager();
+        if (null != sm) {
+            sm.checkSetFactory();
+        }
+
+        NamingManager.ofb = ofb;
+    }
+
+    /**
+     * Create an <code>InitialContext</code> from either a previously
+     * installed <code>InitialContextFactoryBuilder</code> or from the
+     * <code>Context.INITIAL_CONTEXT_FACTORY</code> property in the supplied
+     * <code> Hashtable h</code> if no builder is installed. An installed
+     * <code>InitialContextFactoryBuilder</code> can generate a factory which
+     * can be used to create the <code>InitialContext</code>. The
+     * <code>Context.INITIAL_CONTEXT_FACTORY</code> property contains the
+     * class of a factory which can be used to create the
+     * <code>InitialContext</code>.
+     * 
+     * @param h
+     *            a hashtable containing properties and values - may be null
+     * @return an <code>InitialContext</code>
+     * @throws NoInitialContextException
+     *             if the <code>InitialContext</code> cannot be created.
+     * @throws NamingException
+     */
+    public static Context getInitialContext(Hashtable<?, ?> h)
+            throws NoInitialContextException, NamingException {
+
+        // if InitialContextFactoryBuilder is set
+        if (null != icfb) {
+            // create InitialContext using builder
+            return icfb.createInitialContextFactory(h).getInitialContext(h);
+        }
+
+        // create InitialContext using factory specified in hashtable
+        try {
+            // get factory class name
+            String factoryClassName =
+                (String) h.get(Context.INITIAL_CONTEXT_FACTORY);
+            // new factory instance
+            Class factoryClass = classForName(factoryClassName);
+            InitialContextFactory factory = (InitialContextFactory) factoryClass
+                    .newInstance();
+            // create initial context instance using the factory
+            return factory.getInitialContext(h);
+        } catch (NamingException e) {
+            // throw NamingException
+            throw e;
+        } catch (Exception e) {
+            // failed, throw NoInitialContextException
+            NamingException nex = new NoInitialContextException(
+                    "Failed to create InitialContext using factory specified in hashtable " //$NON-NLS-1$
+                            + h);
+            nex.setRootCause(e);
+            throw nex;
+        }
+    }
+
+    /**
+     * Create an object from either a previously installed
+     * <code>ObjectFactoryBuilder</code> or from a supplied reference or from
+     * the <code>Context.OBJECT_FACTORIES</code> property in the supplied
+     * <code>Hashtable h</code>.
+     * <p>
+     * An installed <code>ObjectFactoryBuilder</code> can generate a factory
+     * which can be used to create the object instance to return to caller. Any
+     * encountered exceptions are thrown.
+     * </p>
+     * <p>
+     * If an <code>ObjectFactoryBuilder</code> has not been installed then the
+     * supplied <code>Object o</code> may provide a <code>Reference</code>
+     * or <code>Referenceable</code> object. If so, then that
+     * <code>Object o</code> may have an associated class in a factory which
+     * could be loaded and used to create the object instance. If the factory
+     * class cannot be loaded then the <code>URLClassLoader</code> may be able
+     * to load a class from the list of URLs specified in the reference's
+     * factory class location. Any exceptions encountered are passed up.
+     * </p>
+     * <p>
+     * If a reference is supplied but no factory class can be loaded from it
+     * then this method returns the supplied object <code>o</code>.
+     * </p>
+     * <p>
+     * If a factory class loads successfully and can then be used to create an
+     * object instance then that instance is returned to the caller.
+     * </p>
+     * <p>
+     * If no factory name was associated with the <code>Reference</code>
+     * object <code>o</code> then see whether the <code>Reference</code> or
+     * <code>Referenceable</code> object has any <code>StringRefAddrs</code>
+     * of address type URL or url in its address list. For each entry in the
+     * list, in the order they appear in the list, it may be possible to use the
+     * URL factory to create the object. A URL in a <code>StringRefAddr</code>
+     * should have a scheme which can be used to locate the associated URL
+     * context factory in the same way as in the <code>getURLContext</code>
+     * method. (The scheme is the part which comes before :\. For example the
+     * URL http://www.apache.org has the scheme http.) A URL with no scheme
+     * would be ignored for these purposes.
+     * </p>
+     * <p>
+     * If no <code>ObjectFactoryBuilder</code> was installed, no factory class
+     * name is supplied with a <code>Reference</code> and no URL contexts
+     * succeeded in creating an <code>Object</code> then try the factories in
+     * <code>Context.OBJECT_FACTORIES</code> for this environment. Also try
+     * the provider resource file belonging to the context <code>c</code>.
+     * (See <code>Context</code> description for details of Provider resource
+     * files.) If any factory throws an exception then pass that back to the
+     * caller - no further factories are tried.
+     * </p>
+     * <p>
+     * If all factories fail to load or create the <code>Object</code> then
+     * return the argument object <code>o</code> as the returned object.
+     * </p>
+     * 
+     * @param o
+     *            an object which may provide reference or location information.
+     *            May be null.
+     * @param n
+     *            The name of the <code>Object</code> relative to the default
+     *            initial context(or relative to the Context c if it is
+     *            supplied)
+     * @param c
+     *            the <code>Context</code> to which the <code>Name</code> is
+     *            relative
+     * @param h
+     *            a <code>Hashtable</code> containing environment properties
+     *            and values - may be null
+     * @return a new <code>Object</code> or the supplied <code>Object o</code>
+     *         if one cannot be created.
+     * @throws NamingException
+     *             if one is encountered
+     * @throws Exception
+     *             if any other exception is encountered
+     */
+    public static Object getObjectInstance(Object o, Name n, Context c,
+            Hashtable<?, ?> h) throws NamingException, Exception {
+
+        // 1. try ObjectFactoryBuilder, if it is set
+        if (null != ofb) {
+            // use the builder to create an object factory
+            ObjectFactory factory = ofb.createObjectFactory(o, h);
+            // get object instance using the factory and return
+            return factory.getObjectInstance(o, n, c, h);
+        }
+
+        // 2. see whether o is a Referenceable or a Reference
+        Reference ref = null;
+        if (o instanceof Referenceable) {
+            ref = ((Referenceable) o).getReference();
+        }
+        if (o instanceof Reference) {
+            ref = (Reference) o;
+        }
+        // if o is a Referenceable or a Reference
+        if (null != ref) {
+            // if a factory class name is supplied by the reference, use it to
+            // create
+            if (null != ref.getFactoryClassName()) {
+                return getObjectInstanceByFactoryInReference(ref, o, n, c, h);
+            }
+            // see if ref has any StringRefAddrs of address type URL,
+            Object result = getObjectInstanceByUrlRefAddr(n, c, h, ref);
+            // if success, return it
+            if (null != result) {
+                return result;
+            }
+        }
+
+        // 3. try Context.OBJECT_FACTORIES
+        Object result = getObjectInstanceByObjectFactory(o, n, c, h);
+        if (null != result) {
+            return result;
+        }
+
+        // all failed, just return o
+        return o;
+    }
+
+    private static Object getObjectInstanceByObjectFactory(Object o, Name n,
+            Context c, Hashtable h) throws NamingException, Exception {
+        // obtain object factories from hashtable and service provider resource
+        // file
+        String fnames[] = EnvironmentReader
+                .getFactoryNamesFromEnvironmentAndProviderResource(h, c,
+                        Context.OBJECT_FACTORIES);
+        for (String element : fnames) {
+            // new factory instance by its class name
+            ObjectFactory factory = null;
+            try {
+                factory = (ObjectFactory) classForName(element).newInstance();
+            } catch (Exception e) {
+                continue;
+            }
+            // create object using factory
+            Object obj = factory.getObjectInstance(o, n, c, h);
+            if (null != obj) {
+                return obj;
+            }
+        }
+        // no object factory succeeded, return null
+        return null;
+    }
+
+    private static Object getObjectInstanceByUrlRefAddr(Name n, Context c,
+            Hashtable h, Reference ref) throws NamingException {
+        // obtain pkg prefixes from hashtable and service provider resource file
+        String pkgPrefixes[] = EnvironmentReader
+                .getFactoryNamesFromEnvironmentAndProviderResource(h, c,
+                        Context.URL_PKG_PREFIXES);
+        // for each RefAddr
+        Enumeration enumeration = ref.getAll();
+        while (enumeration.hasMoreElements()) {
+            RefAddr addr = (RefAddr) enumeration.nextElement();
+            // if it is StringRefAddr and type is URL
+            if (addr instanceof StringRefAddr
+                    && addr.getType().equalsIgnoreCase("URL")) { //$NON-NLS-1$
+                // get the url address
+                String url = (String) ((StringRefAddr) addr).getContent();
+                // try create using url context factory
+                Object obj = getObjectInstanceByUrlContextFactory(url, n, c, h,
+                        pkgPrefixes, UrlParser.getScheme(url));
+                // if success, return the created obj
+                if (null != obj) {
+                    return obj;
+                }
+            }
+        }
+        // failed to create using any StringRefAddr of address type URL, return
+        // null
+        return null;
+    }
+
+    private static Object getObjectInstanceByUrlContextFactory(String url,
+            Name n, Context c, Hashtable h, String pkgPrefixes[], String schema)
+            throws NamingException {
+        // if schema is empty or null, fail, return null
+        if (null == schema || 0 == schema.length()) {
+            return null;
+        }
+
+        for (String element : pkgPrefixes) {
+            ObjectFactory factory = null;
+            try {
+                // create url context factory instance
+                String clsName = element + "." //$NON-NLS-1$
+                        + schema + "." //$NON-NLS-1$
+                        + schema + "URLContextFactory"; //$NON-NLS-1$
+                factory = (ObjectFactory) classForName(clsName).newInstance();
+            } catch (Exception e) {
+                // failed to create factory, continue trying
+                continue;
+            }
+            try {
+                // create obj using url context factory
+                Object obj = factory.getObjectInstance(url, n, c, h);
+                // if create success, return it
+                if (null != obj) {
+                    return obj;
+                }
+            } catch (Exception e) {
+                // throw NamingException, if factory fails
+                if (e instanceof NamingException) {
+                    throw (NamingException) e;
+                }
+                NamingException nex = new NamingException(
+                        "Failed to create object instance"); //$NON-NLS-1$
+                nex.setRootCause(e);
+                throw nex;
+            }
+        }
+        // fail to create using url context factory, return null
+        return null;
+    }
+
+    private static Object getObjectInstanceByFactoryInReference(Reference ref,
+            Object o, Name n, Context c, Hashtable h) throws Exception {
+        ObjectFactory factory = null;
+
+        // try load the factory by its class name
+        try {
+            factory = (ObjectFactory) classForName(ref.getFactoryClassName())
+                    .newInstance();
+        } catch (ClassNotFoundException e) {
+            // Ignore.
+        }
+
+        // try load the factory from its class location
+        if (null == factory && null != ref.getFactoryClassLocation()) {
+            factory = (ObjectFactory) loadFactoryFromLocation(ref
+                    .getFactoryClassName(), ref.getFactoryClassLocation());
+        }
+        // if factory cannot be loaded
+        if (null == factory) {
+            // return o
+            return o;
+        }
+
+        // get object instance using the factory and return it
+        return factory.getObjectInstance(ref, n, c, h);
+    }
+
+    /*
+     * If cannot load class, return null. Throws any exceptions except
+     * ClassNotFoundException
+     */
+    private static Object loadFactoryFromLocation(String clsName,
+            String location) throws Exception {
+
+        // convert location into an array of URL, separated by ' '
+        StringTokenizer st = new StringTokenizer(location, " "); //$NON-NLS-1$
+        URL urls[] = new URL[st.countTokens()];
+        for (int i = 0; i < urls.length; i++) {
+            urls[i] = new URL(st.nextToken());
+        }
+
+        // new a URLClassLoader from the URLs
+        URLClassLoader l = new URLClassLoader(urls);
+
+        // try load factory by URLClassLoader
+        try {
+            // return the new instance
+            return l.loadClass(clsName).newInstance();
+        } catch (ClassNotFoundException e) {
+            // return null if class loading failed
+            return null;
+        }
+    }
+
+    /**
+     * Get the state of an Object.
+     * <p>
+     * The <code>Context.STATE_FACTORIES</code> property from the
+     * <code>Hashtable h</code> together with the
+     * <code>Context.STATE_FACTORIES</code> property from the provider
+     * resource file of the <code>Context c</code> provides the list of
+     * factories tried to get an object's state.
+     * </p>
+     * <p>
+     * Each factory in the list is attempted to be loaded using the context
+     * class loader. Once a class is loaded then it can be used to create a new
+     * instance of it to obtain the factory which can then use its
+     * <code>getStateToBind</code> to find the return object. Once an object
+     * is found then it is not necessary to examine further factories and the
+     * object is returned it as the return parameter.
+     * </p>
+     * <p>
+     * If no factory is loaded or all loaded factories fail to return an object
+     * then return the supplied <code>Object o</code> as the return param.
+     * </p>
+     * <p>
+     * Note for service provider implementors: Classes which implement the
+     * <code>StateFactory</code> interface must be public with a public
+     * constructor that has no parameters.
+     * </p>
+     * 
+     * @param o
+     *            an object which may provide reference or location information.
+     *            May be null.
+     * @param n
+     *            the name of the <code>Object</code> relative to the default
+     *            initial context (or relative to the Context c if it is
+     *            supplied)
+     * @param c
+     *            the <code>Context</code> to which the <code>Name</code> is
+     *            relative
+     * @param h
+     *            a <code>Hashtable</code> containing environment properties
+     *            and values - may be null
+     * @return the state of the specified object
+     * @throws NamingException
+     *             if one is encountered
+     */
+    public static Object getStateToBind(Object o, Name n, Context c, Hashtable h)
+            throws NamingException {
+
+        // obtain state factories from hashtable and service provider resource
+        // file
+        String fnames[] = EnvironmentReader
+                .getFactoryNamesFromEnvironmentAndProviderResource(h, c,
+                        Context.STATE_FACTORIES);
+
+        for (String element : fnames) {
+            // new factory instance by its class name
+            StateFactory factory = null;
+            try {
+                factory = (StateFactory) classForName(element).newInstance();
+            } catch (Exception e) {
+                continue;
+            }
+            // try obtain state using the factory
+            Object state = factory.getStateToBind(o, n, c, h);
+            // if a state obtained successfully, return it
+            if (null != state) {
+                return state;
+            }
+        }
+
+        // all factories failed, return the input argument o
+        return o;
+    }
+
+    /**
+     * Creates a URL <code>Context</code> which can subsequently be used to
+     * resolve any URLs with the URL scheme s. A <code>URLContextFactory</code>
+     * is a type of <code>ObjectFactory</code> used to create a
+     * <code>URLContext</code> when <code>getObjectInstance</code> is
+     * invoked with the <code>Object o</code> set to null (see the description
+     * of <code>ObjectFactory</code>).
+     * <p>
+     * This <code>getURLContext</code> method tries to locate the
+     * <code>URLContextFactory</code> based on the
+     * <code>Context.URL_PKG_PREFIXES</code> property which contains the
+     * prefixes to be tried as the start of the package name. (See
+     * <code>Context</code>).
+     * </p>
+     * <p>
+     * Each package prefix entry (and finally the default value) are tried to
+     * find the class which can be used to create the Context.
+     * </p>
+     * <p>
+     * A full class name is derived as
+     * <code>packageprefix.s.sURLContextFactory</code> where <code>s</code>
+     * is the scheme.
+     * </p>
+     * <p>
+     * For example if a scheme is abc and the package prefix to try is com.ibm
+     * then the factory class to try is
+     * <code>com.ibm.abc.abcURLContextFactory</code>. Once a factory is
+     * created then a <code>Context</code> is created using the special use of
+     * <code>ObjectFactory.getObjectInstance</code>.
+     * </p>
+     * <p>
+     * Once a first factory is created, it is used to create the context, and NO
+     * further attemptions will be made on other pkg prefixes.
+     * </p>
+     * 
+     * @param schema
+     *            the URL scheme to which the Context will relate
+     * @param envmt
+     *            a <code>Hashtable</code> containing environment properties
+     *            and values - may be null
+     * @return the URL <code>Context</code> or null if no
+     *         <code>URLContextFactory</code> instance can be created and
+     *         therefore a Context cannot be created.
+     * @throws NamingException
+     *             if one is encountered.
+     */
+    public static Context getURLContext(String schema, Hashtable<?, ?> envmt)
+            throws NamingException {
+
+        if (null == schema || 0 == schema.length() || null == envmt) {
+            return null;
+        }
+
+        // obtain pkg prefixes from hashtable
+        String pkgPrefixes[] = EnvironmentReader
+                .getFactoryNamesFromEnvironmentAndProviderResource(envmt, null,
+                        Context.URL_PKG_PREFIXES);
+
+        for (String element : pkgPrefixes) {
+            // create factory instance
+            ObjectFactory factory;
+            try {
+                String clsName = element + "." //$NON-NLS-1$
+                        + schema + "." //$NON-NLS-1$
+                        + schema + "URLContextFactory"; //$NON-NLS-1$
+                factory = (ObjectFactory) classForName(clsName).newInstance();
+            } catch (Exception ex) {
+                // fail to create factory, continue to try another
+                continue;
+            }
+            try {
+                // create url context using the factory, and return it
+                return (Context) factory.getObjectInstance(null, null, null,
+                        envmt);
+            } catch (NamingException e) {
+                // find NamingException, throw it
+                throw e;
+            } catch (Exception e) {
+                // other exception, throw as NamingException
+                NamingException nex = new NamingException(
+                        "other exception happens: " + e.toString()); //$NON-NLS-1$
+                nex.setRootCause(e);
+                throw nex;
+            }
+        }
+
+        // cannot create context instance from any pkg prefixes, return null
+        return null;
+    }
+
+    /**
+     * Create the next context when using federation. All the information
+     * required to do this is contained in the
+     * <code>CannotProceedException</code> <code>e</code>. If the resolved
+     * object is null then throw the supplied
+     * <code>CannotProceedException</code> <code>e</code> using the stack
+     * details from this thread. The resolved object in <code>e</code> may
+     * already be a <code>Context</code>. This is the case where the service
+     * provider gives an explicit pointer to the next naming system. A Context
+     * object is returned as the continuation context, but need not be the same
+     * object instance as the resolved object.
+     * <p>
+     * If the resolved object is not already a <code>Context</code> then it is
+     * necessary to use the resolved object together with the
+     * <code>altName</code> name, the <code>altNameCtx</code> context and
+     * the environment hashtable to get an instance of the object. This should
+     * then be a context which is returned as the continuation context. If an
+     * instance cannot be obtained then throw the supplied
+     * <code>CannotProceedException</code> using the stack details from this
+     * thread.
+     * </p>
+     * <p>
+     * This method is responsible for setting the property denoted by the
+     * <code>CPE</code> string to be the supplied
+     * <code>CannotProceedException</code> for the exception <code>e</code>
+     * environment. The continuation context should then inherit this property.
+     * </p>
+     * 
+     * @param cpe
+     *            the <code>CannotProceedException</code> generated by the
+     *            context of the previous naming system when it can proceed no
+     *            further.
+     * @return the next Context when using federation
+     * @throws NamingException
+     *             if the resolved object is null or if a context cannot be
+     *             obtained from it either directly or indirectly.
+     */
+    public static Context getContinuationContext(CannotProceedException cpe)
+            throws NamingException {
+
+        Context ctx = null;
+
+        // set CPE property of the env
+        if (cpe.getEnvironment() == null) {
+            cpe.setEnvironment(new Hashtable<String, CannotProceedException>());
+        }
+        ((Hashtable<String, CannotProceedException>) cpe.getEnvironment()).put(
+                CPE, cpe);
+
+        // if resolved object is null
+        if (null == cpe.getResolvedObj()) {
+            // re-throw cpe
+            cpe.fillInStackTrace();
+            throw cpe;
+        }
+
+        // if cpe's resolved obj is Context
+        if (cpe.getResolvedObj() instanceof Context) {
+            // accept it as the continuation context
+            ctx = (Context) cpe.getResolvedObj();
+        } else {
+            // otherwise, call getObjectInstance() to get a context instance
+            try {
+                ctx = (Context) getObjectInstance(cpe.getResolvedObj(), cpe
+                        .getAltName(), cpe.getAltNameCtx(), cpe
+                        .getEnvironment());
+            } catch (Exception ex) {
+                // throw back CPE in case of any exception
+                throw cpe;
+            }
+            // if ctx cannot be obtained
+            if (null == ctx) {
+                // re-throw CPE
+                cpe.fillInStackTrace();
+                throw cpe;
+            }
+        }
+
+        // return the continuation context
+        return ctx;
+    }
+
+    private static Class classForName(final String className)
+            throws ClassNotFoundException {
+
+        Class cls = AccessController
+                .doPrivileged(new PrivilegedAction<Class>() {
+                    public Class run() {
+                        // try thread context class loader first
+                        try {
+                            return Class.forName(className, true, Thread
+                                    .currentThread().getContextClassLoader());
+                        } catch (ClassNotFoundException e) {
+                            // Ignored.
+                        }
+                        // try system class loader second
+                        try {
+                            return Class.forName(className, true, ClassLoader
+                                    .getSystemClassLoader());
+                        } catch (ClassNotFoundException e1) {
+                            // Ignored.
+                        }
+                        // return null, if fail to load class
+                        return null;
+                    }
+                });
+
+        if (cls == null) {
+            throw new ClassNotFoundException(
+                    "class " + className + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return cls;
+    }
+}