Return-Path: Delivered-To: apmail-incubator-harmony-commits-archive@www.apache.org Received: (qmail 10257 invoked from network); 31 May 2006 21:27:01 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 31 May 2006 21:27:01 -0000 Received: (qmail 4314 invoked by uid 500); 31 May 2006 21:27:00 -0000 Delivered-To: apmail-incubator-harmony-commits-archive@incubator.apache.org Received: (qmail 4224 invoked by uid 500); 31 May 2006 21:27:00 -0000 Mailing-List: contact harmony-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: harmony-dev@incubator.apache.org Delivered-To: mailing list harmony-commits@incubator.apache.org Received: (qmail 4185 invoked by uid 99); 31 May 2006 21:26:59 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 31 May 2006 14:26:59 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 31 May 2006 14:26:57 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 3FA501A983A; Wed, 31 May 2006 14:26:37 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r410674 - /incubator/harmony/enhanced/classlib/trunk/modules/jndi/src/main/java/javax/naming/spi/NamingManager.java Date: Wed, 31 May 2006 21:26:36 -0000 To: harmony-commits@incubator.apache.org From: tellison@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060531212637.3FA501A983A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N 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 NamingManager class should not be instantiated although - * it can be extended by classes within the javax.naming.spi - * package - see {@link DirectoryManager}. All its methods are static. - *

- * 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 Context objects or objects - * referred to by the naming service.

- *

- * The Name and Hashtable arguments passed to the - * NamingManager methods remain owned purely by the calling - * method. They must not be changed or referenced.

- *

- * It should be noted that it is possible for an application to access a - * namespace other than that supplied by the default InitialContext - * (as specified by Context.INITIAL_CONTEXT_FACTORY). It is - * possible to call the following InitialContext methods passing a - * URL string either as the String or Name parameter: - * lookup, bin, rebind, unbind, rename, list, listBindings, - * destroySubcontext, createSubcontext, lookupLink, getNameParser. This - * allows you to have one InitialContext object where these - * methods usually use the default initial context but access a URL - * Context instead when invoked with a URL string.

- *

- * A URL string is of the format abc:\nnnnnn where abc is the scheme of the - * URL. (See InitialContext where it refers to RFC1738.) - * When a URL string is supplied to those InitialContext 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 ObjectFactory. It is not essential that a - * service provider supplies one if they do not wish to support URL - * Contexts.

- *

- * See the getURLContext method for a description of how a URL - * context factory is located.

- *

- * 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 InitialContextFactoryBuilder or - * ObjectFactoryBuilder while another thread is in the process - * of setting it.

- *

- * Also note that privileges should be granted to get the context classloader - * and to read the resource files.

- * - * @see DirectoryManager - */ - -public class NamingManager { - - /* - * ------------------------------------------------------------------- - * Constants - * ------------------------------------------------------------------- - */ - - /** - * The property name of CannotProceedException 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 InitialContextFactoryBuilder. Once this has - * been set it cannot be reset. Attempts to do so cause an - * IllegalStateException. 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 InitialContextFactoryBuilder has - * been installed. - * - * @return true when an InitialContextFactoryBuilder has - * been installed. - */ - public static boolean hasInitialContextFactoryBuilder() { - return null != icfb; - } - - /** - * Install an ObjectFactoryBuilder. Once this has been set - * it cannot be reset. Attempts to do so cause an - * IllegalStateException. The builder can only be installed - * if the security policy allows the setting of the factory. - * - * @param ofb the ObjectFactoryBuilder to be installed - * - can be null, but then no builder is installed. - * @throws IllegalStateException if an ObjectFactoryBuilder - * 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 InitialContext from either a previously - * installed InitialContextFactoryBuilder or from the - * Context.INITIAL_CONTEXT_FACTORY property in the supplied - * Hashtable h if no builder is installed. - * An installed InitialContextFactoryBuilder can generate - * a factory which can be used to create the InitialContext. - * The Context.INITIAL_CONTEXT_FACTORY property contains the - * class of a factory which can be used to create the - * InitialContext. - * - * @param h a hashtable containing properties and values - may be null - * @return an InitialContext - * @throws NoInitialContextException if the InitialContext - * 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 - * ObjectFactoryBuilder or from a supplied reference or - * from the Context.OBJECT_FACTORIES property in the supplied - * Hashtable h. - *

- * An installed ObjectFactoryBuilder can generate a factory - * which can be used to create the object instance to return to caller. - * Any encountered exceptions are thrown.

- *

- * If an ObjectFactoryBuilder has not been installed then - * the supplied Object o may provide a Reference - * or Referenceable object. If so, then that - * Object o 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 URLClassLoader 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.

- *

- * If a reference is supplied but no factory class can be loaded from it - * then this method returns the supplied object o.

- *

- * If a factory class loads successfully and can then be used to create an - * object instance then that instance is returned to the caller.

- *

- * If no factory name was associated with the Reference - * object o then see whether the Reference or - * Referenceable object has any StringRefAddrs - * 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 - * StringRefAddr should have a scheme which can be used to - * locate the associated URL context factory in the same way as in the - * getURLContext 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.

- *

- * If no ObjectFactoryBuilder was installed, no factory - * class name is supplied with a Reference and no URL contexts - * succeeded in creating an Object then try the factories in - * Context.OBJECT_FACTORIES for this environment. Also try - * the provider resource file belonging to the context c. - * (See Context 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.

- *

- * If all factories fail to load or create the Object then - * return the argument object o as the returned object.

- * - * @param o an object which may provide reference or location information. - * May be null. - * @param n The name of the Object relative to the default - * initial context(or relative to the Context c if it is supplied) - * @param c the Context to which the Name is - * relative - * @param h a Hashtable containing environment properties and - * values - may be null - * @return a new Object or the supplied Object o - * 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. - *

- * The Context.STATE_FACTORIES property from the - * Hashtable h together with the - * Context.STATE_FACTORIES property from the provider resource - * file of the Context c provides the list of factories tried - * to get an object's state.

- *

- * 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 - * getStateToBind 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.

- *

- * If no factory is loaded or all loaded factories fail to return an object - * then return the supplied Object o as the return param.

- *

- * Note for service provider implementors: - * Classes which implement the StateFactory interface must be - * public with a public constructor that has no parameters.

- * - * @param o an object which may provide reference or location information. - * May be null. - * @param n the name of the Object relative to the default - * initial context (or relative to the Context c if it is supplied) - * @param c the Context to which the Name is - * relative - * @param h a Hashtable 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 Context which can subsequently be used to - * resolve any URLs with the URL scheme s. A URLContextFactory - * is a type of ObjectFactory used to create a - * URLContext when getObjectInstance is - * invoked with the Object o set to null - * (see the description of ObjectFactory). - *

- * This getURLContext method tries to locate the - * URLContextFactory based on the - * Context.URL_PKG_PREFIXES property which contains the - * prefixes to be tried as the start of the package name. (See - * Context).

- *

- * Each package prefix entry (and finally the default value) are tried to - * find the class which can be used to create the Context.

- *

- * A full class name is derived as - * packageprefix.s.sURLContextFactory where s - * is the scheme.

- *

- * For example if a scheme is abc and the package prefix to try is com.ibm - * then the factory class to try is - * com.ibm.abc.abcURLContextFactory. Once a factory is - * created then a Context is created using the special use of - * ObjectFactory.getObjectInstance.

- *

- * Once a first factory is created, it is used to create the context, - * and NO further attemptions will be made on other pkg prefixes.

- * - * @param schema the URL scheme to which the Context will relate - * @param envmt a Hashtable containing environment - * properties and values - may be null - * @return the URL Context or null if no - * URLContextFactory 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 - * CannotProceedException e. - * If the resolved object is null then throw the supplied - * CannotProceedException e using the stack - * details from this thread. The resolved object in e may - * already be a Context. 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. - *

- * If the resolved object is not already a Context then it is - * necessary to use the resolved object together with the - * altName name, the altNameCtx 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 - * CannotProceedException using the stack details from this - * thread.

- *

- * This method is responsible for setting the property denoted by the - * CPE string to be the supplied - * CannotProceedException for - * the exception e environment. The continuation context - * should then inherit this property.

- * - * @param cpe the CannotProceedException 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()); - } - ((Hashtable)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() { - 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 NamingManager class should not be instantiated although it + * can be extended by classes within the javax.naming.spi package - + * see {@link DirectoryManager}. All its methods are static. + *

+ * 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 Context objects or objects + * referred to by the naming service. + *

+ *

+ * The Name and Hashtable arguments passed to the + * NamingManager methods remain owned purely by the calling + * method. They must not be changed or referenced. + *

+ *

+ * It should be noted that it is possible for an application to access a + * namespace other than that supplied by the default InitialContext + * (as specified by Context.INITIAL_CONTEXT_FACTORY). It is + * possible to call the following InitialContext methods passing + * a URL string either as the String or Name + * parameter: lookup, bin, rebind, unbind, rename, list, listBindings, + * destroySubcontext, createSubcontext, lookupLink, getNameParser. + * This allows you to have one InitialContext object where these + * methods usually use the default initial context but access a URL + * Context instead when invoked with a URL string. + *

+ *

+ * A URL string is of the format abc:\nnnnnn where abc is the scheme of the URL. + * (See InitialContext where it refers to RFC1738.) When a URL + * string is supplied to those InitialContext 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 + * ObjectFactory. It is not essential that a service provider + * supplies one if they do not wish to support URL Contexts. + *

+ *

+ * See the getURLContext method for a description of how a URL + * context factory is located. + *

+ *

+ * 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 InitialContextFactoryBuilder or + * ObjectFactoryBuilder while another thread is in the process of + * setting it. + *

+ *

+ * Also note that privileges should be granted to get the context classloader + * and to read the resource files. + *

+ * + * @see DirectoryManager + */ + +public class NamingManager { + + /* + * ------------------------------------------------------------------- + * Constants + * ------------------------------------------------------------------- + */ + + /** + * The property name of CannotProceedException 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 InitialContextFactoryBuilder. Once this has + * been set it cannot be reset. Attempts to do so cause an + * IllegalStateException. 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 InitialContextFactoryBuilder has been + * installed. + * + * @return true when an InitialContextFactoryBuilder has been + * installed. + */ + public static boolean hasInitialContextFactoryBuilder() { + return null != icfb; + } + + /** + * Install an ObjectFactoryBuilder. Once this has been set + * it cannot be reset. Attempts to do so cause an + * IllegalStateException. The builder can only be installed + * if the security policy allows the setting of the factory. + * + * @param ofb + * the ObjectFactoryBuilder to be installed - can + * be null, but then no builder is installed. + * @throws IllegalStateException + * if an ObjectFactoryBuilder 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 InitialContext from either a previously + * installed InitialContextFactoryBuilder or from the + * Context.INITIAL_CONTEXT_FACTORY property in the supplied + * Hashtable h if no builder is installed. An installed + * InitialContextFactoryBuilder can generate a factory which + * can be used to create the InitialContext. The + * Context.INITIAL_CONTEXT_FACTORY property contains the + * class of a factory which can be used to create the + * InitialContext. + * + * @param h + * a hashtable containing properties and values - may be null + * @return an InitialContext + * @throws NoInitialContextException + * if the InitialContext 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 + * ObjectFactoryBuilder or from a supplied reference or from + * the Context.OBJECT_FACTORIES property in the supplied + * Hashtable h. + *

+ * An installed ObjectFactoryBuilder can generate a factory + * which can be used to create the object instance to return to caller. Any + * encountered exceptions are thrown. + *

+ *

+ * If an ObjectFactoryBuilder has not been installed then the + * supplied Object o may provide a Reference + * or Referenceable object. If so, then that + * Object o 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 URLClassLoader 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. + *

+ *

+ * If a reference is supplied but no factory class can be loaded from it + * then this method returns the supplied object o. + *

+ *

+ * If a factory class loads successfully and can then be used to create an + * object instance then that instance is returned to the caller. + *

+ *

+ * If no factory name was associated with the Reference + * object o then see whether the Reference or + * Referenceable object has any StringRefAddrs + * 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 StringRefAddr + * should have a scheme which can be used to locate the associated URL + * context factory in the same way as in the getURLContext + * 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. + *

+ *

+ * If no ObjectFactoryBuilder was installed, no factory class + * name is supplied with a Reference and no URL contexts + * succeeded in creating an Object then try the factories in + * Context.OBJECT_FACTORIES for this environment. Also try + * the provider resource file belonging to the context c. + * (See Context 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. + *

+ *

+ * If all factories fail to load or create the Object then + * return the argument object o as the returned object. + *

+ * + * @param o + * an object which may provide reference or location information. + * May be null. + * @param n + * The name of the Object relative to the default + * initial context(or relative to the Context c if it is + * supplied) + * @param c + * the Context to which the Name is + * relative + * @param h + * a Hashtable containing environment properties + * and values - may be null + * @return a new Object or the supplied Object o + * 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. + *

+ * The Context.STATE_FACTORIES property from the + * Hashtable h together with the + * Context.STATE_FACTORIES property from the provider + * resource file of the Context c provides the list of + * factories tried to get an object's state. + *

+ *

+ * 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 + * getStateToBind 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. + *

+ *

+ * If no factory is loaded or all loaded factories fail to return an object + * then return the supplied Object o as the return param. + *

+ *

+ * Note for service provider implementors: Classes which implement the + * StateFactory interface must be public with a public + * constructor that has no parameters. + *

+ * + * @param o + * an object which may provide reference or location information. + * May be null. + * @param n + * the name of the Object relative to the default + * initial context (or relative to the Context c if it is + * supplied) + * @param c + * the Context to which the Name is + * relative + * @param h + * a Hashtable 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 Context which can subsequently be used to + * resolve any URLs with the URL scheme s. A URLContextFactory + * is a type of ObjectFactory used to create a + * URLContext when getObjectInstance is + * invoked with the Object o set to null (see the description + * of ObjectFactory). + *

+ * This getURLContext method tries to locate the + * URLContextFactory based on the + * Context.URL_PKG_PREFIXES property which contains the + * prefixes to be tried as the start of the package name. (See + * Context). + *

+ *

+ * Each package prefix entry (and finally the default value) are tried to + * find the class which can be used to create the Context. + *

+ *

+ * A full class name is derived as + * packageprefix.s.sURLContextFactory where s + * is the scheme. + *

+ *

+ * For example if a scheme is abc and the package prefix to try is com.ibm + * then the factory class to try is + * com.ibm.abc.abcURLContextFactory. Once a factory is + * created then a Context is created using the special use of + * ObjectFactory.getObjectInstance. + *

+ *

+ * Once a first factory is created, it is used to create the context, and NO + * further attemptions will be made on other pkg prefixes. + *

+ * + * @param schema + * the URL scheme to which the Context will relate + * @param envmt + * a Hashtable containing environment properties + * and values - may be null + * @return the URL Context or null if no + * URLContextFactory 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 + * CannotProceedException e. If the resolved + * object is null then throw the supplied + * CannotProceedException e using the stack + * details from this thread. The resolved object in e may + * already be a Context. 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. + *

+ * If the resolved object is not already a Context then it is + * necessary to use the resolved object together with the + * altName name, the altNameCtx 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 + * CannotProceedException using the stack details from this + * thread. + *

+ *

+ * This method is responsible for setting the property denoted by the + * CPE string to be the supplied + * CannotProceedException for the exception e + * environment. The continuation context should then inherit this property. + *

+ * + * @param cpe + * the CannotProceedException 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()); + } + ((Hashtable) 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() { + 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; + } +}