diff -r 4ebc2e2fb97c -r 71c04702a3d5 src/java.naming/share/classes/javax/naming/spi/NamingManager.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java.naming/share/classes/javax/naming/spi/NamingManager.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,924 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.naming.spi; + +import java.net.MalformedURLException; +import java.util.*; + + +import javax.naming.*; +import com.sun.naming.internal.VersionHelper; +import com.sun.naming.internal.ResourceManager; +import com.sun.naming.internal.FactoryEnumeration; + +/** + * This class contains methods for creating context objects + * and objects referred to by location information in the naming + * or directory service. + *
+ * This class cannot be instantiated. It has only static methods. + *
+ * The mention of URL in the documentation for this class refers to + * a URL string as defined by RFC 1738 and its related RFCs. It is + * any string that conforms to the syntax described therein, and + * may not always have corresponding support in the java.net.URL + * class or Web browsers. + *
+ * NamingManager is safe for concurrent access by multiple threads. + *
+ * Except as otherwise noted, + * a {@code Name} or environment parameter + * passed to any method is owned by the caller. + * The implementation will not modify the object or keep a reference + * to it, although it may keep a reference to a clone or copy. + * + * @author Rosanna Lee + * @author Scott Seligman + * @since 1.3 + */ + +public class NamingManager { + + /* + * Disallow anyone from creating one of these. + * Made package private so that DirectoryManager can subclass. + */ + + NamingManager() {} + + // should be protected and package private + static final VersionHelper helper = VersionHelper.getVersionHelper(); + +// --------- object factory stuff + + /** + * Package-private; used by DirectoryManager and NamingManager. + */ + private static ObjectFactoryBuilder object_factory_builder = null; + + /** + * The ObjectFactoryBuilder determines the policy used when + * trying to load object factories. + * See getObjectInstance() and class ObjectFactory for a description + * of the default policy. + * setObjectFactoryBuilder() overrides this default policy by installing + * an ObjectFactoryBuilder. Subsequent object factories will + * be loaded and created using the installed builder. + *
+ * The builder can only be installed if the executing thread is allowed + * (by the security manager's checkSetFactory() method) to do so. + * Once installed, the builder cannot be replaced. + * + * @param builder The factory builder to install. If null, no builder + * is installed. + * @exception SecurityException builder cannot be installed + * for security reasons. + * @exception NamingException builder cannot be installed for + * a non-security-related reason. + * @exception IllegalStateException If a factory has already been installed. + * @see #getObjectInstance + * @see ObjectFactory + * @see ObjectFactoryBuilder + * @see java.lang.SecurityManager#checkSetFactory + */ + public static synchronized void setObjectFactoryBuilder( + ObjectFactoryBuilder builder) throws NamingException { + if (object_factory_builder != null) + throw new IllegalStateException("ObjectFactoryBuilder already set"); + + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkSetFactory(); + } + object_factory_builder = builder; + } + + /** + * Used for accessing object factory builder. + */ + static synchronized ObjectFactoryBuilder getObjectFactoryBuilder() { + return object_factory_builder; + } + + + /** + * Retrieves the ObjectFactory for the object identified by a reference, + * using the reference's factory class name and factory codebase + * to load in the factory's class. + * @param ref The non-null reference to use. + * @param factoryName The non-null class name of the factory. + * @return The object factory for the object identified by ref; null + * if unable to load the factory. + */ + static ObjectFactory getObjectFactoryFromReference( + Reference ref, String factoryName) + throws IllegalAccessException, + InstantiationException, + MalformedURLException { + Class> clas = null; + + // Try to use current class loader + try { + clas = helper.loadClass(factoryName); + } catch (ClassNotFoundException e) { + // ignore and continue + // e.printStackTrace(); + } + // All other exceptions are passed up. + + // Not in class path; try to use codebase + String codebase; + if (clas == null && + (codebase = ref.getFactoryClassLocation()) != null) { + try { + clas = helper.loadClass(factoryName, codebase); + } catch (ClassNotFoundException e) { + } + } + + @SuppressWarnings("deprecation") // Class.newInstance + ObjectFactory result = (clas != null) ? (ObjectFactory) clas.newInstance() : null; + return result; + } + + + /** + * Creates an object using the factories specified in the + * {@code Context.OBJECT_FACTORIES} property of the environment + * or of the provider resource file associated with {@code nameCtx}. + * + * @return factory created; null if cannot create + */ + private static Object createObjectFromFactories(Object obj, Name name, + Context nameCtx, Hashtable,?> environment) throws Exception { + + FactoryEnumeration factories = ResourceManager.getFactories( + Context.OBJECT_FACTORIES, environment, nameCtx); + + if (factories == null) + return null; + + // Try each factory until one succeeds + ObjectFactory factory; + Object answer = null; + while (answer == null && factories.hasMore()) { + factory = (ObjectFactory)factories.next(); + answer = factory.getObjectInstance(obj, name, nameCtx, environment); + } + return answer; + } + + private static String getURLScheme(String str) { + int colon_posn = str.indexOf(':'); + int slash_posn = str.indexOf('/'); + + if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn)) + return str.substring(0, colon_posn); + return null; + } + + /** + * Creates an instance of an object for the specified object + * and environment. + *
+ * If an object factory builder has been installed, it is used to + * create a factory for creating the object. + * Otherwise, the following rules are used to create the object: + *
+ * Service providers that implement the {@code DirContext} + * interface should use + * {@code DirectoryManager.getObjectInstance()}, not this method. + * Service providers that implement only the {@code Context} + * interface should use this method. + *
+ * Note that an object factory (an object that implements the ObjectFactory + * interface) must be public and must have a public constructor that + * accepts no arguments. + * In cases where the factory is in a named module then it must be in a + * package which is exported by that module to the {@code java.naming} + * module. + *
+ * The {@code name} and {@code nameCtx} parameters may
+ * optionally be used to specify the name of the object being created.
+ * {@code name} is the name of the object, relative to context
+ * {@code nameCtx}. This information could be useful to the object
+ * factory or to the object implementation.
+ * If there are several possible contexts from which the object
+ * could be named -- as will often be the case -- it is up to
+ * the caller to select one. A good rule of thumb is to select the
+ * "deepest" context available.
+ * If {@code nameCtx} is null, {@code name} is relative
+ * to the default initial context. If no name is being specified, the
+ * {@code name} parameter should be null.
+ *
+ * @param refInfo The possibly null object for which to create an object.
+ * @param name The name of this object relative to {@code nameCtx}.
+ * Specifying a name is optional; if it is
+ * omitted, {@code name} should be null.
+ * @param nameCtx The context relative to which the {@code name}
+ * parameter is specified. If null, {@code name} is
+ * relative to the default initial context.
+ * @param environment The possibly null environment to
+ * be used in the creation of the object factory and the object.
+ * @return An object created using {@code refInfo}; or
+ * {@code refInfo} if an object cannot be created using
+ * the algorithm described above.
+ * @exception NamingException if a naming exception was encountered
+ * while attempting to get a URL context, or if one of the
+ * factories accessed throws a NamingException.
+ * @exception Exception if one of the factories accessed throws an
+ * exception, or if an error was encountered while loading
+ * and instantiating the factory and object classes.
+ * A factory should only throw an exception if it does not want
+ * other factories to be used in an attempt to create an object.
+ * See ObjectFactory.getObjectInstance().
+ * @see #getURLContext
+ * @see ObjectFactory
+ * @see ObjectFactory#getObjectInstance
+ */
+ public static Object
+ getObjectInstance(Object refInfo, Name name, Context nameCtx,
+ Hashtable,?> environment)
+ throws Exception
+ {
+
+ ObjectFactory factory;
+
+ // Use builder if installed
+ ObjectFactoryBuilder builder = getObjectFactoryBuilder();
+ if (builder != null) {
+ // builder must return non-null factory
+ factory = builder.createObjectFactory(refInfo, environment);
+ return factory.getObjectInstance(refInfo, name, nameCtx,
+ environment);
+ }
+
+ // Use reference if possible
+ Reference ref = null;
+ if (refInfo instanceof Reference) {
+ ref = (Reference) refInfo;
+ } else if (refInfo instanceof Referenceable) {
+ ref = ((Referenceable)(refInfo)).getReference();
+ }
+
+ Object answer;
+
+ if (ref != null) {
+ String f = ref.getFactoryClassName();
+ if (f != null) {
+ // if reference identifies a factory, use exclusively
+
+ factory = getObjectFactoryFromReference(ref, f);
+ if (factory != null) {
+ return factory.getObjectInstance(ref, name, nameCtx,
+ environment);
+ }
+ // No factory found, so return original refInfo.
+ // Will reach this point if factory class is not in
+ // class path and reference does not contain a URL for it
+ return refInfo;
+
+ } else {
+ // if reference has no factory, check for addresses
+ // containing URLs
+
+ answer = processURLAddrs(ref, name, nameCtx, environment);
+ if (answer != null) {
+ return answer;
+ }
+ }
+ }
+
+ // try using any specified factories
+ answer =
+ createObjectFromFactories(refInfo, name, nameCtx, environment);
+ return (answer != null) ? answer : refInfo;
+ }
+
+ /*
+ * Ref has no factory. For each address of type "URL", try its URL
+ * context factory. Returns null if unsuccessful in creating and
+ * invoking a factory.
+ */
+ static Object processURLAddrs(Reference ref, Name name, Context nameCtx,
+ Hashtable,?> environment)
+ throws NamingException {
+
+ for (int i = 0; i < ref.size(); i++) {
+ RefAddr addr = ref.get(i);
+ if (addr instanceof StringRefAddr &&
+ addr.getType().equalsIgnoreCase("URL")) {
+
+ String url = (String)addr.getContent();
+ Object answer = processURL(url, name, nameCtx, environment);
+ if (answer != null) {
+ return answer;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static Object processURL(Object refInfo, Name name,
+ Context nameCtx, Hashtable,?> environment)
+ throws NamingException {
+ Object answer;
+
+ // If refInfo is a URL string, try to use its URL context factory
+ // If no context found, continue to try object factories.
+ if (refInfo instanceof String) {
+ String url = (String)refInfo;
+ String scheme = getURLScheme(url);
+ if (scheme != null) {
+ answer = getURLObject(scheme, refInfo, name, nameCtx,
+ environment);
+ if (answer != null) {
+ return answer;
+ }
+ }
+ }
+
+ // If refInfo is an array of URL strings,
+ // try to find a context factory for any one of its URLs.
+ // If no context found, continue to try object factories.
+ if (refInfo instanceof String[]) {
+ String[] urls = (String[])refInfo;
+ for (int i = 0; i
+ * The resulting context is for resolving URLs of the
+ * scheme {@code scheme}. The resulting context is not tied
+ * to a specific URL. It is able to handle arbitrary URLs with
+ * the specified scheme.
+ *
+ * The class name of the factory that creates the resulting context
+ * has the naming convention scheme-idURLContextFactory
+ * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
+ * in the package specified as follows.
+ * The {@code Context.URL_PKG_PREFIXES} environment property (which
+ * may contain values taken from system properties,
+ * or application resource files)
+ * contains a colon-separated list of package prefixes.
+ * Each package prefix in
+ * the property is tried in the order specified to load the factory class.
+ * The default package prefix is "com.sun.jndi.url" (if none of the
+ * specified packages work, this default is tried).
+ * The complete package name is constructed using the package prefix,
+ * concatenated with the scheme id.
+ *
+ * For example, if the scheme id is "ldap", and the
+ * {@code Context.URL_PKG_PREFIXES} property
+ * contains "com.widget:com.wiz.jndi",
+ * the naming manager would attempt to load the following classes
+ * until one is successfully instantiated:
+ *
+ * If a factory is instantiated, it is invoked with the following
+ * parameters to produce the resulting context.
+ *
+ * {@code factory.getObjectInstance(null, environment);}
+ *
+ * For example, invoking getObjectInstance() as shown above
+ * on a LDAP URL context factory would return a
+ * context that can resolve LDAP urls
+ * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
+ * "ldap://ldap.umich.edu/o=umich,c=us", ...).
+ *
+ * Note that an object factory (an object that implements the ObjectFactory
+ * interface) must be public and must have a public constructor that
+ * accepts no arguments.
+ * In cases where the factory is in a named module then it must be in a
+ * package which is exported by that module to the {@code java.naming}
+ * module.
+ *
+ * @param scheme The non-null scheme-id of the URLs supported by the context.
+ * @param environment The possibly null environment properties to be
+ * used in the creation of the object factory and the context.
+ * @return A context for resolving URLs with the
+ * scheme id {@code scheme};
+ * {@code null} if the factory for creating the
+ * context is not found.
+ * @exception NamingException If a naming exception occurs while creating
+ * the context.
+ * @see #getObjectInstance
+ * @see ObjectFactory#getObjectInstance
+ */
+ public static Context getURLContext(String scheme,
+ Hashtable,?> environment)
+ throws NamingException
+ {
+ // pass in 'null' to indicate creation of generic context for scheme
+ // (i.e. not specific to a URL).
+
+ Object answer = getURLObject(scheme, null, null, null, environment);
+ if (answer instanceof Context) {
+ return (Context)answer;
+ } else {
+ return null;
+ }
+ }
+
+ private static final String defaultPkgPrefix = "com.sun.jndi.url";
+
+ /**
+ * Creates an object for the given URL scheme id using
+ * the supplied urlInfo.
+ *
+ * If urlInfo is null, the result is a context for resolving URLs
+ * with the scheme id 'scheme'.
+ * If urlInfo is a URL, the result is a context named by the URL.
+ * Names passed to this context is assumed to be relative to this
+ * context (i.e. not a URL). For example, if urlInfo is
+ * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
+ * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
+ * Subsequent names that can be passed to this context will be
+ * LDAP names relative to this context (e.g. cn="Barbs Jensen").
+ * If urlInfo is an array of URLs, the URLs are assumed
+ * to be equivalent in terms of the context to which they refer.
+ * The resulting context is like that of the single URL case.
+ * If urlInfo is of any other type, that is handled by the
+ * context factory for the URL scheme.
+ * @param scheme the URL scheme id for the context
+ * @param urlInfo information used to create the context
+ * @param name name of this object relative to {@code nameCtx}
+ * @param nameCtx Context whose provider resource file will be searched
+ * for package prefix values (or null if none)
+ * @param environment Environment properties for creating the context
+ * @see javax.naming.InitialContext
+ */
+ private static Object getURLObject(String scheme, Object urlInfo,
+ Name name, Context nameCtx,
+ Hashtable,?> environment)
+ throws NamingException {
+
+ // e.g. "ftpURLContextFactory"
+ ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
+ Context.URL_PKG_PREFIXES, environment, nameCtx,
+ "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
+
+ if (factory == null)
+ return null;
+
+ // Found object factory
+ try {
+ return factory.getObjectInstance(urlInfo, name, nameCtx, environment);
+ } catch (NamingException e) {
+ throw e;
+ } catch (Exception e) {
+ NamingException ne = new NamingException();
+ ne.setRootCause(e);
+ throw ne;
+ }
+
+ }
+
+
+// ------------ Initial Context Factory Stuff
+ private static InitialContextFactoryBuilder initctx_factory_builder = null;
+
+ /**
+ * Use this method for accessing initctx_factory_builder while
+ * inside an unsynchronized method.
+ */
+ private static synchronized InitialContextFactoryBuilder
+ getInitialContextFactoryBuilder() {
+ return initctx_factory_builder;
+ }
+
+ /**
+ * Creates an initial context using the specified environment
+ * properties.
+ *
+ * This is done as follows:
+ *
+ * The builder can only be installed if the executing thread is allowed by
+ * the security manager to do so. Once installed, the builder cannot
+ * be replaced.
+ * @param builder The initial context factory builder to install. If null,
+ * no builder is set.
+ * @exception SecurityException builder cannot be installed for security
+ * reasons.
+ * @exception NamingException builder cannot be installed for
+ * a non-security-related reason.
+ * @exception IllegalStateException If a builder was previous installed.
+ * @see #hasInitialContextFactoryBuilder
+ * @see java.lang.SecurityManager#checkSetFactory
+ */
+ public static synchronized void setInitialContextFactoryBuilder(
+ InitialContextFactoryBuilder builder)
+ throws NamingException {
+ if (initctx_factory_builder != null)
+ throw new IllegalStateException(
+ "InitialContextFactoryBuilder already set");
+
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkSetFactory();
+ }
+ initctx_factory_builder = builder;
+ }
+
+ /**
+ * Determines whether an initial context factory builder has
+ * been set.
+ * @return true if an initial context factory builder has
+ * been set; false otherwise.
+ * @see #setInitialContextFactoryBuilder
+ */
+ public static boolean hasInitialContextFactoryBuilder() {
+ return (getInitialContextFactoryBuilder() != null);
+ }
+
+// ----- Continuation Context Stuff
+
+ /**
+ * Constant that holds the name of the environment property into
+ * which {@code getContinuationContext()} stores the value of its
+ * {@code CannotProceedException} parameter.
+ * This property is inherited by the continuation context, and may
+ * be used by that context's service provider to inspect the
+ * fields of the exception.
+ *
+ * The value of this constant is "java.naming.spi.CannotProceedException".
+ *
+ * @see #getContinuationContext
+ * @since 1.3
+ */
+ public static final String CPE = "java.naming.spi.CannotProceedException";
+
+ /**
+ * Creates a context in which to continue a context operation.
+ *
+ * In performing an operation on a name that spans multiple
+ * namespaces, a context from one naming system may need to pass
+ * the operation on to the next naming system. The context
+ * implementation does this by first constructing a
+ * {@code CannotProceedException} containing information
+ * pinpointing how far it has proceeded. It then obtains a
+ * continuation context from JNDI by calling
+ * {@code getContinuationContext}. The context
+ * implementation should then resume the context operation by
+ * invoking the same operation on the continuation context, using
+ * the remainder of the name that has not yet been resolved.
+ *
+ * Before making use of the {@code cpe} parameter, this method
+ * updates the environment associated with that object by setting
+ * the value of the property {@code CPE}
+ * to {@code cpe}. This property will be inherited by the
+ * continuation context, and may be used by that context's
+ * service provider to inspect the fields of this exception.
+ *
+ * @param cpe
+ * The non-null exception that triggered this continuation.
+ * @return A non-null Context object for continuing the operation.
+ * @exception NamingException If a naming exception occurred.
+ */
+ @SuppressWarnings("unchecked")
+ public static Context getContinuationContext(CannotProceedException cpe)
+ throws NamingException {
+
+ Hashtable
+ *
+ * If none of the package prefixes work, null is returned.
+ *
+ *
+ * @param env The possibly null environment properties used when
+ * creating the context.
+ * @return A non-null initial context.
+ * @exception NoInitialContextException If the
+ * {@code Context.INITIAL_CONTEXT_FACTORY} property
+ * is not found or names a nonexistent
+ * class or a class that cannot be instantiated,
+ * or if the initial context could not be created for some other
+ * reason.
+ * @exception NamingException If some other naming exception was encountered.
+ * @see javax.naming.InitialContext
+ * @see javax.naming.directory.InitialDirContext
+ */
+ public static Context getInitialContext(Hashtable,?> env)
+ throws NamingException {
+ InitialContextFactory factory = null;
+
+ InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
+ if (builder == null) {
+ // No builder installed, use property
+ // Get initial context factory class name
+
+ String className = env != null ?
+ (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
+ if (className == null) {
+ NoInitialContextException ne = new NoInitialContextException(
+ "Need to specify class name in environment or system " +
+ "property, or in an application resource file: " +
+ Context.INITIAL_CONTEXT_FACTORY);
+ throw ne;
+ }
+
+ ServiceLoader
+ *
+ *
+ * (Note that an initial context factory (an object that implements
+ * the InitialContextFactory interface) must be public and must have
+ * a public constructor that accepts no arguments.
+ * In cases where the factory is in a named module then it must
+ * be in a package which is exported by that module to the
+ * {@code java.naming} module.)