1 /*
2 * Copyright 1999-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package javax.naming.spi;
27
28 import java.util.Enumeration;
29 import java.util.Hashtable;
30 import java.util.StringTokenizer;
31 import java.net.MalformedURLException;
32
33 import javax.naming;
34 import com.sun.naming.internal.VersionHelper;
35 import com.sun.naming.internal.ResourceManager;
36 import com.sun.naming.internal.FactoryEnumeration;
37
38 /**
39 * This class contains methods for creating context objects
40 * and objects referred to by location information in the naming
41 * or directory service.
42 *<p>
43 * This class cannot be instantiated. It has only static methods.
44 *<p>
45 * The mention of URL in the documentation for this class refers to
46 * a URL string as defined by RFC 1738 and its related RFCs. It is
47 * any string that conforms to the syntax described therein, and
48 * may not always have corresponding support in the java.net.URL
49 * class or Web browsers.
50 *<p>
51 * NamingManager is safe for concurrent access by multiple threads.
52 *<p>
53 * Except as otherwise noted,
54 * a <tt>Name</tt> or environment parameter
55 * passed to any method is owned by the caller.
56 * The implementation will not modify the object or keep a reference
57 * to it, although it may keep a reference to a clone or copy.
58 *
59 * @author Rosanna Lee
60 * @author Scott Seligman
61 * @since 1.3
62 */
63
64 public class NamingManager {
65
66 /*
67 * Disallow anyone from creating one of these.
68 * Made package private so that DirectoryManager can subclass.
69 */
70
71 NamingManager() {}
72
73 // should be protected and package private
74 static final VersionHelper helper = VersionHelper.getVersionHelper();
75
76 // --------- object factory stuff
77
78 /**
79 * Package-private; used by DirectoryManager and NamingManager.
80 */
81 private static ObjectFactoryBuilder object_factory_builder = null;
82
83 /**
84 * The ObjectFactoryBuilder determines the policy used when
85 * trying to load object factories.
86 * See getObjectInstance() and class ObjectFactory for a description
87 * of the default policy.
88 * setObjectFactoryBuilder() overrides this default policy by installing
89 * an ObjectFactoryBuilder. Subsequent object factories will
90 * be loaded and created using the installed builder.
91 *<p>
92 * The builder can only be installed if the executing thread is allowed
93 * (by the security manager's checkSetFactory() method) to do so.
94 * Once installed, the builder cannot be replaced.
95 *<p>
96 * @param builder The factory builder to install. If null, no builder
97 * is installed.
98 * @exception SecurityException builder cannot be installed
99 * for security reasons.
100 * @exception NamingException builder cannot be installed for
101 * a non-security-related reason.
102 * @exception IllegalStateException If a factory has already been installed.
103 * @see #getObjectInstance
104 * @see ObjectFactory
105 * @see ObjectFactoryBuilder
106 * @see java.lang.SecurityManager#checkSetFactory
107 */
108 public static synchronized void setObjectFactoryBuilder(
109 ObjectFactoryBuilder builder) throws NamingException {
110 if (object_factory_builder != null)
111 throw new IllegalStateException("ObjectFactoryBuilder already set");
112
113 SecurityManager security = System.getSecurityManager();
114 if (security != null) {
115 security.checkSetFactory();
116 }
117 object_factory_builder = builder;
118 }
119
120 /**
121 * Used for accessing object factory builder.
122 */
123 static synchronized ObjectFactoryBuilder getObjectFactoryBuilder() {
124 return object_factory_builder;
125 }
126
127
128 /**
129 * Retrieves the ObjectFactory for the object identified by a reference,
130 * using the reference's factory class name and factory codebase
131 * to load in the factory's class.
132 * @param ref The non-null reference to use.
133 * @param factoryName The non-null class name of the factory.
134 * @return The object factory for the object identified by ref; null
135 * if unable to load the factory.
136 */
137 static ObjectFactory getObjectFactoryFromReference(
138 Reference ref, String factoryName)
139 throws IllegalAccessException,
140 InstantiationException,
141 MalformedURLException {
142 Class clas = null;
143
144 // Try to use current class loader
145 try {
146 clas = helper.loadClass(factoryName);
147 } catch (ClassNotFoundException e) {
148 // ignore and continue
149 // e.printStackTrace();
150 }
151 // All other exceptions are passed up.
152
153 // Not in class path; try to use codebase
154 String codebase;
155 if (clas == null &&
156 (codebase = ref.getFactoryClassLocation()) != null) {
157 try {
158 clas = helper.loadClass(factoryName, codebase);
159 } catch (ClassNotFoundException e) {
160 }
161 }
162
163 return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
164 }
165
166
167 /**
168 * Creates an object using the factories specified in the
169 * <tt>Context.OBJECT_FACTORIES</tt> property of the environment
170 * or of the provider resource file associated with <tt>nameCtx</tt>.
171 *
172 * @return factory created; null if cannot create
173 */
174 private static Object createObjectFromFactories(Object obj, Name name,
175 Context nameCtx, Hashtable environment) throws Exception {
176
177 FactoryEnumeration factories = ResourceManager.getFactories(
178 Context.OBJECT_FACTORIES, environment, nameCtx);
179
180 if (factories == null)
181 return null;
182
183 // Try each factory until one succeeds
184 ObjectFactory factory;
185 Object answer = null;
186 while (answer == null && factories.hasMore()) {
187 factory = (ObjectFactory)factories.next();
188 answer = factory.getObjectInstance(obj, name, nameCtx, environment);
189 }
190 return answer;
191 }
192
193 private static String getURLScheme(String str) {
194 int colon_posn = str.indexOf(':');
195 int slash_posn = str.indexOf('/');
196
197 if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
198 return str.substring(0, colon_posn);
199 return null;
200 }
201
202 /**
203 * Creates an instance of an object for the specified object
204 * and environment.
205 * <p>
206 * If an object factory builder has been installed, it is used to
207 * create a factory for creating the object.
208 * Otherwise, the following rules are used to create the object:
209 *<ol>
210 * <li>If <code>refInfo</code> is a <code>Reference</code>
211 * or <code>Referenceable</code> containing a factory class name,
212 * use the named factory to create the object.
213 * Return <code>refInfo</code> if the factory cannot be created.
214 * Under JDK 1.1, if the factory class must be loaded from a location
215 * specified in the reference, a <tt>SecurityManager</tt> must have
216 * been installed or the factory creation will fail.
217 * If an exception is encountered while creating the factory,
218 * it is passed up to the caller.
219 * <li>If <tt>refInfo</tt> is a <tt>Reference</tt> or
220 * <tt>Referenceable</tt> with no factory class name,
221 * and the address or addresses are <tt>StringRefAddr</tt>s with
222 * address type "URL",
223 * try the URL context factory corresponding to each URL's scheme id
224 * to create the object (see <tt>getURLContext()</tt>).
225 * If that fails, continue to the next step.
226 * <li> Use the object factories specified in
227 * the <tt>Context.OBJECT_FACTORIES</tt> property of the environment,
228 * and of the provider resource file associated with
229 * <tt>nameCtx</tt>, in that order.
230 * The value of this property is a colon-separated list of factory
231 * class names that are tried in order, and the first one that succeeds
232 * in creating an object is the one used.
233 * If none of the factories can be loaded,
234 * return <code>refInfo</code>.
235 * If an exception is encountered while creating the object, the
236 * exception is passed up to the caller.
237 *</ol>
238 *<p>
239 * Service providers that implement the <tt>DirContext</tt>
240 * interface should use
241 * <tt>DirectoryManager.getObjectInstance()</tt>, not this method.
242 * Service providers that implement only the <tt>Context</tt>
243 * interface should use this method.
244 * <p>
245 * Note that an object factory (an object that implements the ObjectFactory
246 * interface) must be public and must have a public constructor that
247 * accepts no arguments.
248 * <p>
249 * The <code>name</code> and <code>nameCtx</code> parameters may
250 * optionally be used to specify the name of the object being created.
251 * <code>name</code> is the name of the object, relative to context
252 * <code>nameCtx</code>. This information could be useful to the object
253 * factory or to the object implementation.
254 * If there are several possible contexts from which the object
255 * could be named -- as will often be the case -- it is up to
256 * the caller to select one. A good rule of thumb is to select the
257 * "deepest" context available.
258 * If <code>nameCtx</code> is null, <code>name</code> is relative
259 * to the default initial context. If no name is being specified, the
260 * <code>name</code> parameter should be null.
261 *
262 * @param refInfo The possibly null object for which to create an object.
263 * @param name The name of this object relative to <code>nameCtx</code>.
264 * Specifying a name is optional; if it is
265 * omitted, <code>name</code> should be null.
266 * @param nameCtx The context relative to which the <code>name</code>
267 * parameter is specified. If null, <code>name</code> is
268 * relative to the default initial context.
269 * @param environment The possibly null environment to
270 * be used in the creation of the object factory and the object.
271 * @return An object created using <code>refInfo</code>; or
272 * <code>refInfo</code> if an object cannot be created using
273 * the algorithm described above.
274 * @exception NamingException if a naming exception was encountered
275 * while attempting to get a URL context, or if one of the
276 * factories accessed throws a NamingException.
277 * @exception Exception if one of the factories accessed throws an
278 * exception, or if an error was encountered while loading
279 * and instantiating the factory and object classes.
280 * A factory should only throw an exception if it does not want
281 * other factories to be used in an attempt to create an object.
282 * See ObjectFactory.getObjectInstance().
283 * @see #getURLContext
284 * @see ObjectFactory
285 * @see ObjectFactory#getObjectInstance
286 */
287 public static Object
288 getObjectInstance(Object refInfo, Name name, Context nameCtx,
289 Hashtable<?,?> environment)
290 throws Exception
291 {
292
293 ObjectFactory factory;
294
295 // Use builder if installed
296 ObjectFactoryBuilder builder = getObjectFactoryBuilder();
297 if (builder != null) {
298 // builder must return non-null factory
299 factory = builder.createObjectFactory(refInfo, environment);
300 return factory.getObjectInstance(refInfo, name, nameCtx,
301 environment);
302 }
303
304 // Use reference if possible
305 Reference ref = null;
306 if (refInfo instanceof Reference) {
307 ref = (Reference) refInfo;
308 } else if (refInfo instanceof Referenceable) {
309 ref = ((Referenceable)(refInfo)).getReference();
310 }
311
312 Object answer;
313
314 if (ref != null) {
315 String f = ref.getFactoryClassName();
316 if (f != null) {
317 // if reference identifies a factory, use exclusively
318
319 factory = getObjectFactoryFromReference(ref, f);
320 if (factory != null) {
321 return factory.getObjectInstance(ref, name, nameCtx,
322 environment);
323 }
324 // No factory found, so return original refInfo.
325 // Will reach this point if factory class is not in
326 // class path and reference does not contain a URL for it
327 return refInfo;
328
329 } else {
330 // if reference has no factory, check for addresses
331 // containing URLs
332
333 answer = processURLAddrs(ref, name, nameCtx, environment);
334 if (answer != null) {
335 return answer;
336 }
337 }
338 }
339
340 // try using any specified factories
341 answer =
342 createObjectFromFactories(refInfo, name, nameCtx, environment);
343 return (answer != null) ? answer : refInfo;
344 }
345
346 /*
347 * Ref has no factory. For each address of type "URL", try its URL
348 * context factory. Returns null if unsuccessful in creating and
349 * invoking a factory.
350 */
351 static Object processURLAddrs(Reference ref, Name name, Context nameCtx,
352 Hashtable environment)
353 throws NamingException {
354
355 for (int i = 0; i < ref.size(); i++) {
356 RefAddr addr = ref.get(i);
357 if (addr instanceof StringRefAddr &&
358 addr.getType().equalsIgnoreCase("URL")) {
359
360 String url = (String)addr.getContent();
361 Object answer = processURL(url, name, nameCtx, environment);
362 if (answer != null) {
363 return answer;
364 }
365 }
366 }
367 return null;
368 }
369
370 private static Object processURL(Object refInfo, Name name,
371 Context nameCtx, Hashtable environment)
372 throws NamingException {
373 Object answer;
374
375 // If refInfo is a URL string, try to use its URL context factory
376 // If no context found, continue to try object factories.
377 if (refInfo instanceof String) {
378 String url = (String)refInfo;
379 String scheme = getURLScheme(url);
380 if (scheme != null) {
381 answer = getURLObject(scheme, refInfo, name, nameCtx,
382 environment);
383 if (answer != null) {
384 return answer;
385 }
386 }
387 }
388
389 // If refInfo is an array of URL strings,
390 // try to find a context factory for any one of its URLs.
391 // If no context found, continue to try object factories.
392 if (refInfo instanceof String[]) {
393 String[] urls = (String[])refInfo;
394 for (int i = 0; i <urls.length; i++) {
395 String scheme = getURLScheme(urls[i]);
396 if (scheme != null) {
397 answer = getURLObject(scheme, refInfo, name, nameCtx,
398 environment);
399 if (answer != null)
400 return answer;
401 }
402 }
403 }
404 return null;
405 }
406
407
408 /**
409 * Retrieves a context identified by <code>obj</code>, using the specified
410 * environment.
411 * Used by ContinuationContext.
412 *
413 * @param obj The object identifying the context.
414 * @param name The name of the context being returned, relative to
415 * <code>nameCtx</code>, or null if no name is being
416 * specified.
417 * See the <code>getObjectInstance</code> method for
418 * details.
419 * @param ctx The context relative to which <code>name</code> is
420 * specified, or null for the default initial context.
421 * See the <code>getObjectInstance</code> method for
422 * details.
423 * @param environment Environment specifying characteristics of the
424 * resulting context.
425 * @return A context identified by <code>obj</code>.
426 *
427 * @see #getObjectInstance
428 */
429 static Context getContext(Object obj, Name name, Context nameCtx,
430 Hashtable environment) throws NamingException {
431 Object answer;
432
433 if (obj instanceof Context) {
434 // %%% Ignore environment for now. OK since method not public.
435 return (Context)obj;
436 }
437
438 try {
439 answer = getObjectInstance(obj, name, nameCtx, environment);
440 } catch (NamingException e) {
441 throw e;
442 } catch (Exception e) {
443 NamingException ne = new NamingException();
444 ne.setRootCause(e);
445 throw ne;
446 }
447
448 return (answer instanceof Context)
449 ? (Context)answer
450 : null;
451 }
452
453 // Used by ContinuationContext
454 static Resolver getResolver(Object obj, Name name, Context nameCtx,
455 Hashtable environment) throws NamingException {
456 Object answer;
457
458 if (obj instanceof Resolver) {
459 // %%% Ignore environment for now. OK since method not public.
460 return (Resolver)obj;
461 }
462
463 try {
464 answer = getObjectInstance(obj, name, nameCtx, environment);
465 } catch (NamingException e) {
466 throw e;
467 } catch (Exception e) {
468 NamingException ne = new NamingException();
469 ne.setRootCause(e);
470 throw ne;
471 }
472
473 return (answer instanceof Resolver)
474 ? (Resolver)answer
475 : null;
476 }
477
478
479 /***************** URL Context implementations ***************/
480
481 /**
482 * Creates a context for the given URL scheme id.
483 * <p>
484 * The resulting context is for resolving URLs of the
485 * scheme <code>scheme</code>. The resulting context is not tied
486 * to a specific URL. It is able to handle arbitrary URLs with
487 * the specified scheme.
488 *<p>
489 * The class name of the factory that creates the resulting context
490 * has the naming convention <i>scheme-id</i>URLContextFactory
491 * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
492 * in the package specified as follows.
493 * The <tt>Context.URL_PKG_PREFIXES</tt> environment property (which
494 * may contain values taken from applet parameters, system properties,
495 * or application resource files)
496 * contains a colon-separated list of package prefixes.
497 * Each package prefix in
498 * the property is tried in the order specified to load the factory class.
499 * The default package prefix is "com.sun.jndi.url" (if none of the
500 * specified packages work, this default is tried).
501 * The complete package name is constructed using the package prefix,
502 * concatenated with the scheme id.
503 *<p>
504 * For example, if the scheme id is "ldap", and the
505 * <tt>Context.URL_PKG_PREFIXES</tt> property
506 * contains "com.widget:com.wiz.jndi",
507 * the naming manager would attempt to load the following classes
508 * until one is successfully instantiated:
509 *<ul>
510 * <li>com.widget.ldap.ldapURLContextFactory
511 * <li>com.wiz.jndi.ldap.ldapURLContextFactory
512 * <li>com.sun.jndi.url.ldap.ldapURLContextFactory
513 *</ul>
514 * If none of the package prefixes work, null is returned.
515 *<p>
516 * If a factory is instantiated, it is invoked with the following
517 * parameters to produce the resulting context.
518 * <p>
519 * <code>factory.getObjectInstance(null, environment);</code>
520 * <p>
521 * For example, invoking getObjectInstance() as shown above
522 * on a LDAP URL context factory would return a
523 * context that can resolve LDAP urls
524 * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
525 * "ldap://ldap.umich.edu/o=umich,c=us", ...).
526 *<p>
527 * Note that an object factory (an object that implements the ObjectFactory
528 * interface) must be public and must have a public constructor that
529 * accepts no arguments.
530 *
531 * @param scheme The non-null scheme-id of the URLs supported by the context.
532 * @param environment The possibly null environment properties to be
533 * used in the creation of the object factory and the context.
534 * @return A context for resolving URLs with the
535 * scheme id <code>scheme</code>;
536 * <code>null</code> if the factory for creating the
537 * context is not found.
538 * @exception NamingException If a naming exception occurs while creating
539 * the context.
540 * @see #getObjectInstance
541 * @see ObjectFactory#getObjectInstance
542 */
543 public static Context getURLContext(String scheme,
544 Hashtable<?,?> environment)
545 throws NamingException
546 {
547 // pass in 'null' to indicate creation of generic context for scheme
548 // (i.e. not specific to a URL).
549
550 Object answer = getURLObject(scheme, null, null, null, environment);
551 if (answer instanceof Context) {
552 return (Context)answer;
553 } else {
554 return null;
555 }
556 }
557
558 private static final String defaultPkgPrefix = "com.sun.jndi.url";
559
560 /**
561 * Creates an object for the given URL scheme id using
562 * the supplied urlInfo.
563 * <p>
564 * If urlInfo is null, the result is a context for resolving URLs
565 * with the scheme id 'scheme'.
566 * If urlInfo is a URL, the result is a context named by the URL.
567 * Names passed to this context is assumed to be relative to this
568 * context (i.e. not a URL). For example, if urlInfo is
569 * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
570 * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
571 * Subsequent names that can be passed to this context will be
572 * LDAP names relative to this context (e.g. cn="Barbs Jensen").
573 * If urlInfo is an array of URLs, the URLs are assumed
574 * to be equivalent in terms of the context to which they refer.
575 * The resulting context is like that of the single URL case.
576 * If urlInfo is of any other type, that is handled by the
577 * context factory for the URL scheme.
578 * @param scheme the URL scheme id for the context
579 * @param urlInfo information used to create the context
580 * @param name name of this object relative to <code>nameCtx</code>
581 * @param nameCtx Context whose provider resource file will be searched
582 * for package prefix values (or null if none)
583 * @param environment Environment properties for creating the context
584 * @see javax.naming.InitialContext
585 */
586 private static Object getURLObject(String scheme, Object urlInfo,
587 Name name, Context nameCtx,
588 Hashtable environment)
589 throws NamingException {
590
591 // e.g. "ftpURLContextFactory"
592 ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
593 Context.URL_PKG_PREFIXES, environment, nameCtx,
594 "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
595
596 if (factory == null)
597 return null;
598
599 // Found object factory
600 try {
601 return factory.getObjectInstance(urlInfo, name, nameCtx, environment);
602 } catch (NamingException e) {
603 throw e;
604 } catch (Exception e) {
605 NamingException ne = new NamingException();
606 ne.setRootCause(e);
607 throw ne;
608 }
609
610 }
611
612
613 // ------------ Initial Context Factory Stuff
614 private static InitialContextFactoryBuilder initctx_factory_builder = null;
615
616 /**
617 * Use this method for accessing initctx_factory_builder while
618 * inside an unsynchronized method.
619 */
620 private static synchronized InitialContextFactoryBuilder
621 getInitialContextFactoryBuilder() {
622 return initctx_factory_builder;
623 }
624
625 /**
626 * Creates an initial context using the specified environment
627 * properties.
628 *<p>
629 * If an InitialContextFactoryBuilder has been installed,
630 * it is used to create the factory for creating the initial context.
631 * Otherwise, the class specified in the
632 * <tt>Context.INITIAL_CONTEXT_FACTORY</tt> environment property is used.
633 * Note that an initial context factory (an object that implements the
634 * InitialContextFactory interface) must be public and must have a
635 * public constructor that accepts no arguments.
636 *
637 * @param env The possibly null environment properties used when
638 * creating the context.
639 * @return A non-null initial context.
640 * @exception NoInitialContextException If the
641 * <tt>Context.INITIAL_CONTEXT_FACTORY</tt> property
642 * is not found or names a nonexistent
643 * class or a class that cannot be instantiated,
644 * or if the initial context could not be created for some other
645 * reason.
646 * @exception NamingException If some other naming exception was encountered.
647 * @see javax.naming.InitialContext
648 * @see javax.naming.directory.InitialDirContext
649 */
650 public static Context getInitialContext(Hashtable<?,?> env)
651 throws NamingException {
652 InitialContextFactory factory;
653
654 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
655 if (builder == null) {
656 // No factory installed, use property
657 // Get initial context factory class name
658
659 String className = env != null ?
660 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
661 if (className == null) {
662 NoInitialContextException ne = new NoInitialContextException(
663 "Need to specify class name in environment or system " +
664 "property, or as an applet parameter, or in an " +
665 "application resource file: " +
666 Context.INITIAL_CONTEXT_FACTORY);
667 throw ne;
668 }
669
670 try {
671 factory = (InitialContextFactory)
672 helper.loadClass(className).newInstance();
673 } catch(Exception e) {
674 NoInitialContextException ne =
675 new NoInitialContextException(
676 "Cannot instantiate class: " + className);
677 ne.setRootCause(e);
678 throw ne;
679 }
680 } else {
681 factory = builder.createInitialContextFactory(env);
682 }
683
684 return factory.getInitialContext(env);
685 }
686
687
688 /**
689 * Sets the InitialContextFactory builder to be builder.
690 *
691 *<p>
692 * The builder can only be installed if the executing thread is allowed by
693 * the security manager to do so. Once installed, the builder cannot
694 * be replaced.
695 * @param builder The initial context factory builder to install. If null,
696 * no builder is set.
697 * @exception SecurityException builder cannot be installed for security
698 * reasons.
699 * @exception NamingException builder cannot be installed for
700 * a non-security-related reason.
701 * @exception IllegalStateException If a builder was previous installed.
702 * @see #hasInitialContextFactoryBuilder
703 * @see java.lang.SecurityManager#checkSetFactory
704 */
705 public static synchronized void setInitialContextFactoryBuilder(
706 InitialContextFactoryBuilder builder)
707 throws NamingException {
708 if (initctx_factory_builder != null)
709 throw new IllegalStateException(
710 "InitialContextFactoryBuilder already set");
711
712 SecurityManager security = System.getSecurityManager();
713 if (security != null) {
714 security.checkSetFactory();
715 }
716 initctx_factory_builder = builder;
717 }
718
719 /**
720 * Determines whether an initial context factory builder has
721 * been set.
722 * @return true if an initial context factory builder has
723 * been set; false otherwise.
724 * @see #setInitialContextFactoryBuilder
725 */
726 public static boolean hasInitialContextFactoryBuilder() {
727 return (getInitialContextFactoryBuilder() != null);
728 }
729
730 // ----- Continuation Context Stuff
731
732 /**
733 * Constant that holds the name of the environment property into
734 * which <tt>getContinuationContext()</tt> stores the value of its
735 * <tt>CannotProceedException</tt> parameter.
736 * This property is inherited by the continuation context, and may
737 * be used by that context's service provider to inspect the
738 * fields of the exception.
739 *<p>
740 * The value of this constant is "java.naming.spi.CannotProceedException".
741 *
742 * @see #getContinuationContext
743 * @since 1.3
744 */
745 public static final String CPE = "java.naming.spi.CannotProceedException";
746
747 /**
748 * Creates a context in which to continue a context operation.
749 *<p>
750 * In performing an operation on a name that spans multiple
751 * namespaces, a context from one naming system may need to pass
752 * the operation on to the next naming system. The context
753 * implementation does this by first constructing a
754 * <code>CannotProceedException</code> containing information
755 * pinpointing how far it has proceeded. It then obtains a
756 * continuation context from JNDI by calling
757 * <code>getContinuationContext</code>. The context
758 * implementation should then resume the context operation by
759 * invoking the same operation on the continuation context, using
760 * the remainder of the name that has not yet been resolved.
761 *<p>
762 * Before making use of the <tt>cpe</tt> parameter, this method
763 * updates the environment associated with that object by setting
764 * the value of the property <a href="#CPE"><tt>CPE</tt></a>
765 * to <tt>cpe</tt>. This property will be inherited by the
766 * continuation context, and may be used by that context's
767 * service provider to inspect the fields of this exception.
768 *
769 * @param cpe
770 * The non-null exception that triggered this continuation.
771 * @return A non-null Context object for continuing the operation.
772 * @exception NamingException If a naming exception occurred.
773 */
774 public static Context getContinuationContext(CannotProceedException cpe)
775 throws NamingException {
776
777 Hashtable env = cpe.getEnvironment();
778 if (env == null) {
779 env = new Hashtable(7);
780 } else {
781 // Make a (shallow) copy of the environment.
782 env = (Hashtable) env.clone();
783 }
784 env.put(CPE, cpe);
785
786 ContinuationContext cctx = new ContinuationContext(cpe, env);
787 return cctx.getTargetContext();
788 }
789
790 // ------------ State Factory Stuff
791
792 /**
793 * Retrieves the state of an object for binding.
794 * <p>
795 * Service providers that implement the <tt>DirContext</tt> interface
796 * should use <tt>DirectoryManager.getStateToBind()</tt>, not this method.
797 * Service providers that implement only the <tt>Context</tt> interface
798 * should use this method.
799 *<p>
800 * This method uses the specified state factories in
801 * the <tt>Context.STATE_FACTORIES</tt> property from the environment
802 * properties, and from the provider resource file associated with
803 * <tt>nameCtx</tt>, in that order.
804 * The value of this property is a colon-separated list of factory
805 * class names that are tried in order, and the first one that succeeds
806 * in returning the object's state is the one used.
807 * If no object's state can be retrieved in this way, return the
808 * object itself.
809 * If an exception is encountered while retrieving the state, the
810 * exception is passed up to the caller.
811 * <p>
812 * Note that a state factory
813 * (an object that implements the StateFactory
814 * interface) must be public and must have a public constructor that
815 * accepts no arguments.
816 * <p>
817 * The <code>name</code> and <code>nameCtx</code> parameters may
818 * optionally be used to specify the name of the object being created.
819 * See the description of "Name and Context Parameters" in
820 * {@link ObjectFactory#getObjectInstance
821 * ObjectFactory.getObjectInstance()}
822 * for details.
823 * <p>
824 * This method may return a <tt>Referenceable</tt> object. The
825 * service provider obtaining this object may choose to store it
826 * directly, or to extract its reference (using
827 * <tt>Referenceable.getReference()</tt>) and store that instead.
828 *
829 * @param obj The non-null object for which to get state to bind.
830 * @param name The name of this object relative to <code>nameCtx</code>,
831 * or null if no name is specified.
832 * @param nameCtx The context relative to which the <code>name</code>
833 * parameter is specified, or null if <code>name</code> is
834 * relative to the default initial context.
835 * @param environment The possibly null environment to
836 * be used in the creation of the state factory and
837 * the object's state.
838 * @return The non-null object representing <tt>obj</tt>'s state for
839 * binding. It could be the object (<tt>obj</tt>) itself.
840 * @exception NamingException If one of the factories accessed throws an
841 * exception, or if an error was encountered while loading
842 * and instantiating the factory and object classes.
843 * A factory should only throw an exception if it does not want
844 * other factories to be used in an attempt to create an object.
845 * See <tt>StateFactory.getStateToBind()</tt>.
846 * @see StateFactory
847 * @see StateFactory#getStateToBind
848 * @see DirectoryManager#getStateToBind
849 * @since 1.3
850 */
851 public static Object
852 getStateToBind(Object obj, Name name, Context nameCtx,
853 Hashtable<?,?> environment)
854 throws NamingException
855 {
856
857 FactoryEnumeration factories = ResourceManager.getFactories(
858 Context.STATE_FACTORIES, environment, nameCtx);
859
860 if (factories == null) {
861 return obj;
862 }
863
864 // Try each factory until one succeeds
865 StateFactory factory;
866 Object answer = null;
867 while (answer == null && factories.hasMore()) {
868 factory = (StateFactory)factories.next();
869 answer = factory.getStateToBind(obj, name, nameCtx, environment);
870 }
871
872 return (answer != null) ? answer : obj;
873 }
874 }