Path: blob/master/src/java.naming/share/classes/javax/naming/spi/NamingManager.java
41159 views
/*1* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.naming.spi;2627import java.net.MalformedURLException;28import java.security.AccessController;29import java.security.PrivilegedAction;30import java.util.*;3132import javax.naming.*;3334import com.sun.naming.internal.ObjectFactoriesFilter;35import com.sun.naming.internal.VersionHelper;36import com.sun.naming.internal.ResourceManager;37import com.sun.naming.internal.FactoryEnumeration;38import jdk.internal.loader.ClassLoaderValue;3940/**41* This class contains methods for creating context objects42* and objects referred to by location information in the naming43* or directory service.44*<p>45* This class cannot be instantiated. It has only static methods.46*<p>47* The mention of URL in the documentation for this class refers to48* a URL string as defined by RFC 1738 and its related RFCs. It is49* any string that conforms to the syntax described therein, and50* may not always have corresponding support in the java.net.URL51* class or Web browsers.52*<p>53* NamingManager is safe for concurrent access by multiple threads.54*<p>55* Except as otherwise noted,56* a {@code Name} or environment parameter57* passed to any method is owned by the caller.58* The implementation will not modify the object or keep a reference59* to it, although it may keep a reference to a clone or copy.60*61* @author Rosanna Lee62* @author Scott Seligman63* @since 1.364*/6566public class NamingManager {6768/*69* Disallow anyone from creating one of these.70* Made package private so that DirectoryManager can subclass.71*/7273NamingManager() {}7475// should be protected and package private76static final VersionHelper helper = VersionHelper.getVersionHelper();7778// --------- object factory stuff7980/**81* Package-private; used by DirectoryManager and NamingManager.82*/83private static ObjectFactoryBuilder object_factory_builder = null;8485private static final ClassLoaderValue<InitialContextFactory> FACTORIES_CACHE =86new ClassLoaderValue<>();8788/**89* The ObjectFactoryBuilder determines the policy used when90* trying to load object factories.91* See getObjectInstance() and class ObjectFactory for a description92* of the default policy.93* setObjectFactoryBuilder() overrides this default policy by installing94* an ObjectFactoryBuilder. Subsequent object factories will95* be loaded and created using the installed builder.96*<p>97* The builder can only be installed if the executing thread is allowed98* (by the security manager's checkSetFactory() method) to do so.99* Once installed, the builder cannot be replaced.100*101* @param builder The factory builder to install. If null, no builder102* is installed.103* @throws SecurityException builder cannot be installed104* for security reasons.105* @throws NamingException builder cannot be installed for106* a non-security-related reason.107* @throws IllegalStateException If a factory has already been installed.108* @see #getObjectInstance109* @see ObjectFactory110* @see ObjectFactoryBuilder111* @see java.lang.SecurityManager#checkSetFactory112*/113public static synchronized void setObjectFactoryBuilder(114ObjectFactoryBuilder builder) throws NamingException {115if (object_factory_builder != null)116throw new IllegalStateException("ObjectFactoryBuilder already set");117118@SuppressWarnings("removal")119SecurityManager security = System.getSecurityManager();120if (security != null) {121security.checkSetFactory();122}123object_factory_builder = builder;124}125126/**127* Used for accessing object factory builder.128*/129static synchronized ObjectFactoryBuilder getObjectFactoryBuilder() {130return object_factory_builder;131}132133134/**135* Retrieves the ObjectFactory for the object identified by a reference,136* using the reference's factory class name and factory codebase137* to load in the factory's class.138* @param ref The non-null reference to use.139* @param factoryName The non-null class name of the factory.140* @return The object factory for the object identified by ref; null141* if unable to load the factory.142*/143static ObjectFactory getObjectFactoryFromReference(144Reference ref, String factoryName)145throws IllegalAccessException,146InstantiationException,147MalformedURLException {148Class<?> clas = null;149150// Try to use current class loader151try {152clas = helper.loadClassWithoutInit(factoryName);153// Validate factory's class with the objects factory serial filter154if (!ObjectFactoriesFilter.canInstantiateObjectsFactory(clas)) {155return null;156}157} catch (ClassNotFoundException e) {158// ignore and continue159// e.printStackTrace();160}161// All other exceptions are passed up.162163// Not in class path; try to use codebase164String codebase;165if (clas == null &&166(codebase = ref.getFactoryClassLocation()) != null) {167try {168clas = helper.loadClass(factoryName, codebase);169// Validate factory's class with the objects factory serial filter170if (clas == null ||171!ObjectFactoriesFilter.canInstantiateObjectsFactory(clas)) {172return null;173}174} catch (ClassNotFoundException e) {175}176}177178@SuppressWarnings("deprecation") // Class.newInstance179ObjectFactory result = (clas != null) ? (ObjectFactory) clas.newInstance() : null;180return result;181}182183184/**185* Creates an object using the factories specified in the186* {@code Context.OBJECT_FACTORIES} property of the environment187* or of the provider resource file associated with {@code nameCtx}.188*189* @return factory created; null if cannot create190*/191private static Object createObjectFromFactories(Object obj, Name name,192Context nameCtx, Hashtable<?,?> environment) throws Exception {193194FactoryEnumeration factories = ResourceManager.getFactories(195Context.OBJECT_FACTORIES, environment, nameCtx);196197if (factories == null)198return null;199200// Try each factory until one succeeds201ObjectFactory factory;202Object answer = null;203while (answer == null && factories.hasMore()) {204factory = (ObjectFactory)factories.next();205answer = factory.getObjectInstance(obj, name, nameCtx, environment);206}207return answer;208}209210private static String getURLScheme(String str) {211int colon_posn = str.indexOf(':');212int slash_posn = str.indexOf('/');213214if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))215return str.substring(0, colon_posn);216return null;217}218219/**220* Creates an instance of an object for the specified object221* and environment.222* <p>223* If an object factory builder has been installed, it is used to224* create a factory for creating the object.225* Otherwise, the following rules are used to create the object:226*<ol>227* <li>If {@code refInfo} is a {@code Reference}228* or {@code Referenceable} containing a factory class name,229* use the named factory to create the object.230* Return {@code refInfo} if the factory cannot be created.231* Under JDK 1.1, if the factory class must be loaded from a location232* specified in the reference, a {@code SecurityManager} must have233* been installed or the factory creation will fail.234* If an exception is encountered while creating the factory,235* it is passed up to the caller.236* <li>If {@code refInfo} is a {@code Reference} or237* {@code Referenceable} with no factory class name,238* and the address or addresses are {@code StringRefAddr}s with239* address type "URL",240* try the URL context factory corresponding to each URL's scheme id241* to create the object (see {@code getURLContext()}).242* If that fails, continue to the next step.243* <li> Use the object factories specified in244* the {@code Context.OBJECT_FACTORIES} property of the environment,245* and of the provider resource file associated with246* {@code nameCtx}, in that order.247* The value of this property is a colon-separated list of factory248* class names that are tried in order, and the first one that succeeds249* in creating an object is the one used.250* If none of the factories can be loaded,251* return {@code refInfo}.252* If an exception is encountered while creating the object, the253* exception is passed up to the caller.254*</ol>255*<p>256* Service providers that implement the {@code DirContext}257* interface should use258* {@code DirectoryManager.getObjectInstance()}, not this method.259* Service providers that implement only the {@code Context}260* interface should use this method.261* <p>262* Note that an object factory (an object that implements the ObjectFactory263* interface) must be public and must have a public constructor that264* accepts no arguments.265* In cases where the factory is in a named module then it must be in a266* package which is exported by that module to the {@code java.naming}267* module.268* <p>269* The {@code name} and {@code nameCtx} parameters may270* optionally be used to specify the name of the object being created.271* {@code name} is the name of the object, relative to context272* {@code nameCtx}. This information could be useful to the object273* factory or to the object implementation.274* If there are several possible contexts from which the object275* could be named -- as will often be the case -- it is up to276* the caller to select one. A good rule of thumb is to select the277* "deepest" context available.278* If {@code nameCtx} is null, {@code name} is relative279* to the default initial context. If no name is being specified, the280* {@code name} parameter should be null.281*282* @param refInfo The possibly null object for which to create an object.283* @param name The name of this object relative to {@code nameCtx}.284* Specifying a name is optional; if it is285* omitted, {@code name} should be null.286* @param nameCtx The context relative to which the {@code name}287* parameter is specified. If null, {@code name} is288* relative to the default initial context.289* @param environment The possibly null environment to290* be used in the creation of the object factory and the object.291* @return An object created using {@code refInfo}; or292* {@code refInfo} if an object cannot be created using293* the algorithm described above.294* @throws NamingException if a naming exception was encountered295* while attempting to get a URL context, or if one of the296* factories accessed throws a NamingException.297* @throws Exception if one of the factories accessed throws an298* exception, or if an error was encountered while loading299* and instantiating the factory and object classes.300* A factory should only throw an exception if it does not want301* other factories to be used in an attempt to create an object.302* See ObjectFactory.getObjectInstance().303* @see #getURLContext304* @see ObjectFactory305* @see ObjectFactory#getObjectInstance306*/307public static Object308getObjectInstance(Object refInfo, Name name, Context nameCtx,309Hashtable<?,?> environment)310throws Exception311{312313ObjectFactory factory;314315// Use builder if installed316ObjectFactoryBuilder builder = getObjectFactoryBuilder();317if (builder != null) {318// builder must return non-null factory319factory = builder.createObjectFactory(refInfo, environment);320return factory.getObjectInstance(refInfo, name, nameCtx,321environment);322}323324// Use reference if possible325Reference ref = null;326if (refInfo instanceof Reference) {327ref = (Reference) refInfo;328} else if (refInfo instanceof Referenceable) {329ref = ((Referenceable)(refInfo)).getReference();330}331332Object answer;333334if (ref != null) {335String f = ref.getFactoryClassName();336if (f != null) {337// if reference identifies a factory, use exclusively338339factory = getObjectFactoryFromReference(ref, f);340if (factory != null) {341return factory.getObjectInstance(ref, name, nameCtx,342environment);343}344// No factory found, so return original refInfo.345// Will reach this point if factory class is not in346// class path and reference does not contain a URL for it347return refInfo;348349} else {350// if reference has no factory, check for addresses351// containing URLs352353answer = processURLAddrs(ref, name, nameCtx, environment);354if (answer != null) {355return answer;356}357}358}359360// try using any specified factories361answer =362createObjectFromFactories(refInfo, name, nameCtx, environment);363return (answer != null) ? answer : refInfo;364}365366/*367* Ref has no factory. For each address of type "URL", try its URL368* context factory. Returns null if unsuccessful in creating and369* invoking a factory.370*/371static Object processURLAddrs(Reference ref, Name name, Context nameCtx,372Hashtable<?,?> environment)373throws NamingException {374375for (int i = 0; i < ref.size(); i++) {376RefAddr addr = ref.get(i);377if (addr instanceof StringRefAddr &&378addr.getType().equalsIgnoreCase("URL")) {379380String url = (String)addr.getContent();381Object answer = processURL(url, name, nameCtx, environment);382if (answer != null) {383return answer;384}385}386}387return null;388}389390private static Object processURL(Object refInfo, Name name,391Context nameCtx, Hashtable<?,?> environment)392throws NamingException {393Object answer;394395// If refInfo is a URL string, try to use its URL context factory396// If no context found, continue to try object factories.397if (refInfo instanceof String) {398String url = (String)refInfo;399String scheme = getURLScheme(url);400if (scheme != null) {401answer = getURLObject(scheme, refInfo, name, nameCtx,402environment);403if (answer != null) {404return answer;405}406}407}408409// If refInfo is an array of URL strings,410// try to find a context factory for any one of its URLs.411// If no context found, continue to try object factories.412if (refInfo instanceof String[]) {413String[] urls = (String[])refInfo;414for (int i = 0; i <urls.length; i++) {415String scheme = getURLScheme(urls[i]);416if (scheme != null) {417answer = getURLObject(scheme, refInfo, name, nameCtx,418environment);419if (answer != null)420return answer;421}422}423}424return null;425}426427428/**429* Retrieves a context identified by {@code obj}, using the specified430* environment.431* Used by ContinuationContext.432*433* @param obj The object identifying the context.434* @param name The name of the context being returned, relative to435* {@code nameCtx}, or null if no name is being436* specified.437* See the {@code getObjectInstance} method for438* details.439* @param nameCtx The context relative to which {@code name} is440* specified, or null for the default initial context.441* See the {@code getObjectInstance} method for442* details.443* @param environment Environment specifying characteristics of the444* resulting context.445* @return A context identified by {@code obj}.446*447* @see #getObjectInstance448*/449static Context getContext(Object obj, Name name, Context nameCtx,450Hashtable<?,?> environment) throws NamingException {451Object answer;452453if (obj instanceof Context) {454// %%% Ignore environment for now. OK since method not public.455return (Context)obj;456}457458try {459answer = getObjectInstance(obj, name, nameCtx, environment);460} catch (NamingException e) {461throw e;462} catch (Exception e) {463NamingException ne = new NamingException();464ne.setRootCause(e);465throw ne;466}467468return (answer instanceof Context)469? (Context)answer470: null;471}472473// Used by ContinuationContext474static Resolver getResolver(Object obj, Name name, Context nameCtx,475Hashtable<?,?> environment) throws NamingException {476Object answer;477478if (obj instanceof Resolver) {479// %%% Ignore environment for now. OK since method not public.480return (Resolver)obj;481}482483try {484answer = getObjectInstance(obj, name, nameCtx, environment);485} catch (NamingException e) {486throw e;487} catch (Exception e) {488NamingException ne = new NamingException();489ne.setRootCause(e);490throw ne;491}492493return (answer instanceof Resolver)494? (Resolver)answer495: null;496}497498499/***************** URL Context implementations ***************/500501/**502* Creates a context for the given URL scheme id.503* <p>504* The resulting context is for resolving URLs of the505* scheme {@code scheme}. The resulting context is not tied506* to a specific URL. It is able to handle arbitrary URLs with507* the specified scheme.508*<p>509* The class name of the factory that creates the resulting context510* has the naming convention <i>scheme-id</i>URLContextFactory511* (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),512* in the package specified as follows.513* The {@code Context.URL_PKG_PREFIXES} environment property (which514* may contain values taken from system properties,515* or application resource files)516* contains a colon-separated list of package prefixes.517* Each package prefix in518* the property is tried in the order specified to load the factory class.519* The default package prefix is "com.sun.jndi.url" (if none of the520* specified packages work, this default is tried).521* The complete package name is constructed using the package prefix,522* concatenated with the scheme id.523*<p>524* For example, if the scheme id is "ldap", and the525* {@code Context.URL_PKG_PREFIXES} property526* contains "com.widget:com.wiz.jndi",527* the naming manager would attempt to load the following classes528* until one is successfully instantiated:529*<ul>530* <li>com.widget.ldap.ldapURLContextFactory531* <li>com.wiz.jndi.ldap.ldapURLContextFactory532* <li>com.sun.jndi.url.ldap.ldapURLContextFactory533*</ul>534* If none of the package prefixes work, null is returned.535*<p>536* If a factory is instantiated, it is invoked with the following537* parameters to produce the resulting context.538* <p>539* {@code factory.getObjectInstance(null, environment);}540* <p>541* For example, invoking getObjectInstance() as shown above542* on a LDAP URL context factory would return a543* context that can resolve LDAP urls544* (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",545* "ldap://ldap.umich.edu/o=umich,c=us", ...).546*<p>547* Note that an object factory (an object that implements the ObjectFactory548* interface) must be public and must have a public constructor that549* accepts no arguments.550* In cases where the factory is in a named module then it must be in a551* package which is exported by that module to the {@code java.naming}552* module.553*554* @param scheme The non-null scheme-id of the URLs supported by the context.555* @param environment The possibly null environment properties to be556* used in the creation of the object factory and the context.557* @return A context for resolving URLs with the558* scheme id {@code scheme};559* {@code null} if the factory for creating the560* context is not found.561* @throws NamingException If a naming exception occurs while creating562* the context.563* @see #getObjectInstance564* @see ObjectFactory#getObjectInstance565*/566public static Context getURLContext(String scheme,567Hashtable<?,?> environment)568throws NamingException569{570// pass in 'null' to indicate creation of generic context for scheme571// (i.e. not specific to a URL).572573Object answer = getURLObject(scheme, null, null, null, environment);574if (answer instanceof Context) {575return (Context)answer;576} else {577return null;578}579}580581private static final String defaultPkgPrefix = "com.sun.jndi.url";582583/**584* Creates an object for the given URL scheme id using585* the supplied urlInfo.586* <p>587* If urlInfo is null, the result is a context for resolving URLs588* with the scheme id 'scheme'.589* If urlInfo is a URL, the result is a context named by the URL.590* Names passed to this context is assumed to be relative to this591* context (i.e. not a URL). For example, if urlInfo is592* "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will593* be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.594* Subsequent names that can be passed to this context will be595* LDAP names relative to this context (e.g. cn="Barbs Jensen").596* If urlInfo is an array of URLs, the URLs are assumed597* to be equivalent in terms of the context to which they refer.598* The resulting context is like that of the single URL case.599* If urlInfo is of any other type, that is handled by the600* context factory for the URL scheme.601* @param scheme the URL scheme id for the context602* @param urlInfo information used to create the context603* @param name name of this object relative to {@code nameCtx}604* @param nameCtx Context whose provider resource file will be searched605* for package prefix values (or null if none)606* @param environment Environment properties for creating the context607* @see javax.naming.InitialContext608*/609private static Object getURLObject(String scheme, Object urlInfo,610Name name, Context nameCtx,611Hashtable<?,?> environment)612throws NamingException {613614// e.g. "ftpURLContextFactory"615ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(616Context.URL_PKG_PREFIXES, environment, nameCtx,617"." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);618619if (factory == null)620return null;621622// Found object factory623try {624return factory.getObjectInstance(urlInfo, name, nameCtx, environment);625} catch (NamingException e) {626throw e;627} catch (Exception e) {628NamingException ne = new NamingException();629ne.setRootCause(e);630throw ne;631}632633}634635636// ------------ Initial Context Factory Stuff637private static InitialContextFactoryBuilder initctx_factory_builder = null;638639/**640* Use this method for accessing initctx_factory_builder while641* inside an unsynchronized method.642*/643private static synchronized InitialContextFactoryBuilder644getInitialContextFactoryBuilder() {645return initctx_factory_builder;646}647648/**649* Creates an initial context using the specified environment650* properties.651* <p>652* This is done as follows:653* <ul>654* <li>If an InitialContextFactoryBuilder has been installed,655* it is used to create the factory for creating the initial656* context</li>657* <li>Otherwise, the class specified in the658* {@code Context.INITIAL_CONTEXT_FACTORY} environment property659* is used660* <ul>661* <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader}662* mechanism tries to locate an {@code InitialContextFactory}663* provider using the current thread's context class loader</li>664* <li>Failing that, this implementation tries to locate a suitable665* {@code InitialContextFactory} using a built-in mechanism666* <br>667* (Note that an initial context factory (an object that implements668* the InitialContextFactory interface) must be public and must have669* a public constructor that accepts no arguments.670* In cases where the factory is in a named module then it must671* be in a package which is exported by that module to the672* {@code java.naming} module.)</li>673* </ul>674* </li>675* </ul>676* @param env The possibly null environment properties used when677* creating the context.678* @return A non-null initial context.679* @throws NoInitialContextException If the680* {@code Context.INITIAL_CONTEXT_FACTORY} property681* is not found or names a nonexistent682* class or a class that cannot be instantiated,683* or if the initial context could not be created for some other684* reason.685* @throws NamingException If some other naming exception was encountered.686* @see javax.naming.InitialContext687* @see javax.naming.directory.InitialDirContext688*/689@SuppressWarnings("removal")690public static Context getInitialContext(Hashtable<?,?> env)691throws NamingException {692ClassLoader loader;693InitialContextFactory factory = null;694695InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();696if (builder == null) {697// No builder installed, use property698// Get initial context factory class name699700String className = env != null ?701(String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;702if (className == null) {703NoInitialContextException ne = new NoInitialContextException(704"Need to specify class name in environment or system " +705"property, or in an application resource file: " +706Context.INITIAL_CONTEXT_FACTORY);707throw ne;708}709710if (System.getSecurityManager() == null) {711loader = Thread.currentThread().getContextClassLoader();712if (loader == null) loader = ClassLoader.getSystemClassLoader();713} else {714PrivilegedAction<ClassLoader> pa = () -> {715ClassLoader cl = Thread.currentThread().getContextClassLoader();716return (cl == null) ? ClassLoader.getSystemClassLoader() : cl;717};718loader = AccessController.doPrivileged(pa);719}720721var key = FACTORIES_CACHE.sub(className);722try {723factory = key.computeIfAbsent(loader, (ld, ky) -> getFactory(ky.key()));724} catch (FactoryInitializationError e) {725throw e.getCause();726}727} else {728factory = builder.createInitialContextFactory(env);729}730731return factory.getInitialContext(env);732}733734private static InitialContextFactory getFactory(String className) {735InitialContextFactory factory;736try {737ServiceLoader<InitialContextFactory> loader =738ServiceLoader.load(InitialContextFactory.class);739740factory = loader741.stream()742.filter(p -> p.type().getName().equals(className))743.findFirst()744.map(ServiceLoader.Provider::get)745.orElse(null);746} catch (ServiceConfigurationError e) {747NoInitialContextException ne =748new NoInitialContextException(749"Cannot load initial context factory "750+ "'" + className + "'");751ne.setRootCause(e);752throw new FactoryInitializationError(ne);753}754755if (factory == null) {756try {757@SuppressWarnings("deprecation")758Object o = helper.loadClass(className).newInstance();759factory = (InitialContextFactory) o;760} catch (Exception e) {761NoInitialContextException ne =762new NoInitialContextException(763"Cannot instantiate class: " + className);764ne.setRootCause(e);765throw new FactoryInitializationError(ne);766}767}768return factory;769}770771772/**773* Sets the InitialContextFactory builder to be builder.774*775*<p>776* The builder can only be installed if the executing thread is allowed by777* the security manager to do so. Once installed, the builder cannot778* be replaced.779* @param builder The initial context factory builder to install. If null,780* no builder is set.781* @throws SecurityException builder cannot be installed for security782* reasons.783* @throws NamingException builder cannot be installed for784* a non-security-related reason.785* @throws IllegalStateException If a builder was previous installed.786* @see #hasInitialContextFactoryBuilder787* @see java.lang.SecurityManager#checkSetFactory788*/789public static synchronized void setInitialContextFactoryBuilder(790InitialContextFactoryBuilder builder)791throws NamingException {792if (initctx_factory_builder != null)793throw new IllegalStateException(794"InitialContextFactoryBuilder already set");795796@SuppressWarnings("removal")797SecurityManager security = System.getSecurityManager();798if (security != null) {799security.checkSetFactory();800}801initctx_factory_builder = builder;802}803804/**805* Determines whether an initial context factory builder has806* been set.807* @return true if an initial context factory builder has808* been set; false otherwise.809* @see #setInitialContextFactoryBuilder810*/811public static boolean hasInitialContextFactoryBuilder() {812return (getInitialContextFactoryBuilder() != null);813}814815// ----- Continuation Context Stuff816817/**818* Constant that holds the name of the environment property into819* which {@code getContinuationContext()} stores the value of its820* {@code CannotProceedException} parameter.821* This property is inherited by the continuation context, and may822* be used by that context's service provider to inspect the823* fields of the exception.824*<p>825* The value of this constant is "java.naming.spi.CannotProceedException".826*827* @see #getContinuationContext828* @since 1.3829*/830public static final String CPE = "java.naming.spi.CannotProceedException";831832/**833* Creates a context in which to continue a context operation.834*<p>835* In performing an operation on a name that spans multiple836* namespaces, a context from one naming system may need to pass837* the operation on to the next naming system. The context838* implementation does this by first constructing a839* {@code CannotProceedException} containing information840* pinpointing how far it has proceeded. It then obtains a841* continuation context from JNDI by calling842* {@code getContinuationContext}. The context843* implementation should then resume the context operation by844* invoking the same operation on the continuation context, using845* the remainder of the name that has not yet been resolved.846*<p>847* Before making use of the {@code cpe} parameter, this method848* updates the environment associated with that object by setting849* the value of the property <a href="#CPE">{@code CPE}</a>850* to {@code cpe}. This property will be inherited by the851* continuation context, and may be used by that context's852* service provider to inspect the fields of this exception.853*854* @param cpe855* The non-null exception that triggered this continuation.856* @return A non-null Context object for continuing the operation.857* @throws NamingException If a naming exception occurred.858*/859@SuppressWarnings("unchecked")860public static Context getContinuationContext(CannotProceedException cpe)861throws NamingException {862863Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment();864if (env == null) {865env = new Hashtable<>(7);866} else {867// Make a (shallow) copy of the environment.868env = (Hashtable<Object,Object>)env.clone();869}870env.put(CPE, cpe);871872ContinuationContext cctx = new ContinuationContext(cpe, env);873return cctx.getTargetContext();874}875876// ------------ State Factory Stuff877878/**879* Retrieves the state of an object for binding.880* <p>881* Service providers that implement the {@code DirContext} interface882* should use {@code DirectoryManager.getStateToBind()}, not this method.883* Service providers that implement only the {@code Context} interface884* should use this method.885*<p>886* This method uses the specified state factories in887* the {@code Context.STATE_FACTORIES} property from the environment888* properties, and from the provider resource file associated with889* {@code nameCtx}, in that order.890* The value of this property is a colon-separated list of factory891* class names that are tried in order, and the first one that succeeds892* in returning the object's state is the one used.893* If no object's state can be retrieved in this way, return the894* object itself.895* If an exception is encountered while retrieving the state, the896* exception is passed up to the caller.897* <p>898* Note that a state factory899* (an object that implements the StateFactory900* interface) must be public and must have a public constructor that901* accepts no arguments.902* In cases where the factory is in a named module then it must be in a903* package which is exported by that module to the {@code java.naming}904* module.905* <p>906* The {@code name} and {@code nameCtx} parameters may907* optionally be used to specify the name of the object being created.908* See the description of "Name and Context Parameters" in909* {@link ObjectFactory#getObjectInstance910* ObjectFactory.getObjectInstance()}911* for details.912* <p>913* This method may return a {@code Referenceable} object. The914* service provider obtaining this object may choose to store it915* directly, or to extract its reference (using916* {@code Referenceable.getReference()}) and store that instead.917*918* @param obj The non-null object for which to get state to bind.919* @param name The name of this object relative to {@code nameCtx},920* or null if no name is specified.921* @param nameCtx The context relative to which the {@code name}922* parameter is specified, or null if {@code name} is923* relative to the default initial context.924* @param environment The possibly null environment to925* be used in the creation of the state factory and926* the object's state.927* @return The non-null object representing {@code obj}'s state for928* binding. It could be the object ({@code obj}) itself.929* @throws NamingException If one of the factories accessed throws an930* exception, or if an error was encountered while loading931* and instantiating the factory and object classes.932* A factory should only throw an exception if it does not want933* other factories to be used in an attempt to create an object.934* See {@code StateFactory.getStateToBind()}.935* @see StateFactory936* @see StateFactory#getStateToBind937* @see DirectoryManager#getStateToBind938* @since 1.3939*/940public static Object941getStateToBind(Object obj, Name name, Context nameCtx,942Hashtable<?,?> environment)943throws NamingException944{945946FactoryEnumeration factories = ResourceManager.getFactories(947Context.STATE_FACTORIES, environment, nameCtx);948949if (factories == null) {950return obj;951}952953// Try each factory until one succeeds954StateFactory factory;955Object answer = null;956while (answer == null && factories.hasMore()) {957factory = (StateFactory)factories.next();958answer = factory.getStateToBind(obj, name, nameCtx, environment);959}960961return (answer != null) ? answer : obj;962}963964/**965* Thrown when an error is encountered while loading and instantiating the966* context factory classes.967*/968private static class FactoryInitializationError extends Error {969@java.io.Serial970static final long serialVersionUID = -5805552256848841560L;971972private FactoryInitializationError(NoInitialContextException cause) {973super(cause);974}975976@Override977public NoInitialContextException getCause() {978return (NoInitialContextException) super.getCause();979}980}981}982983984