32 import com.sun.naming.internal.VersionHelper;
33 import com.sun.naming.internal.ResourceManager;
34 import com.sun.naming.internal.FactoryEnumeration;
35
36 /**
37 * This class contains methods for creating context objects
38 * and objects referred to by location information in the naming
39 * or directory service.
40 *<p>
41 * This class cannot be instantiated. It has only static methods.
42 *<p>
43 * The mention of URL in the documentation for this class refers to
44 * a URL string as defined by RFC 1738 and its related RFCs. It is
45 * any string that conforms to the syntax described therein, and
46 * may not always have corresponding support in the java.net.URL
47 * class or Web browsers.
48 *<p>
49 * NamingManager is safe for concurrent access by multiple threads.
50 *<p>
51 * Except as otherwise noted,
52 * a <tt>Name</tt> or environment parameter
53 * passed to any method is owned by the caller.
54 * The implementation will not modify the object or keep a reference
55 * to it, although it may keep a reference to a clone or copy.
56 *
57 * @author Rosanna Lee
58 * @author Scott Seligman
59 * @since 1.3
60 */
61
62 public class NamingManager {
63
64 /*
65 * Disallow anyone from creating one of these.
66 * Made package private so that DirectoryManager can subclass.
67 */
68
69 NamingManager() {}
70
71 // should be protected and package private
72 static final VersionHelper helper = VersionHelper.getVersionHelper();
147 // e.printStackTrace();
148 }
149 // All other exceptions are passed up.
150
151 // Not in class path; try to use codebase
152 String codebase;
153 if (clas == null &&
154 (codebase = ref.getFactoryClassLocation()) != null) {
155 try {
156 clas = helper.loadClass(factoryName, codebase);
157 } catch (ClassNotFoundException e) {
158 }
159 }
160
161 return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
162 }
163
164
165 /**
166 * Creates an object using the factories specified in the
167 * <tt>Context.OBJECT_FACTORIES</tt> property of the environment
168 * or of the provider resource file associated with <tt>nameCtx</tt>.
169 *
170 * @return factory created; null if cannot create
171 */
172 private static Object createObjectFromFactories(Object obj, Name name,
173 Context nameCtx, Hashtable<?,?> environment) throws Exception {
174
175 FactoryEnumeration factories = ResourceManager.getFactories(
176 Context.OBJECT_FACTORIES, environment, nameCtx);
177
178 if (factories == null)
179 return null;
180
181 // Try each factory until one succeeds
182 ObjectFactory factory;
183 Object answer = null;
184 while (answer == null && factories.hasMore()) {
185 factory = (ObjectFactory)factories.next();
186 answer = factory.getObjectInstance(obj, name, nameCtx, environment);
187 }
188 return answer;
189 }
190
191 private static String getURLScheme(String str) {
192 int colon_posn = str.indexOf(':');
193 int slash_posn = str.indexOf('/');
194
195 if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
196 return str.substring(0, colon_posn);
197 return null;
198 }
199
200 /**
201 * Creates an instance of an object for the specified object
202 * and environment.
203 * <p>
204 * If an object factory builder has been installed, it is used to
205 * create a factory for creating the object.
206 * Otherwise, the following rules are used to create the object:
207 *<ol>
208 * <li>If <code>refInfo</code> is a <code>Reference</code>
209 * or <code>Referenceable</code> containing a factory class name,
210 * use the named factory to create the object.
211 * Return <code>refInfo</code> if the factory cannot be created.
212 * Under JDK 1.1, if the factory class must be loaded from a location
213 * specified in the reference, a <tt>SecurityManager</tt> must have
214 * been installed or the factory creation will fail.
215 * If an exception is encountered while creating the factory,
216 * it is passed up to the caller.
217 * <li>If <tt>refInfo</tt> is a <tt>Reference</tt> or
218 * <tt>Referenceable</tt> with no factory class name,
219 * and the address or addresses are <tt>StringRefAddr</tt>s with
220 * address type "URL",
221 * try the URL context factory corresponding to each URL's scheme id
222 * to create the object (see <tt>getURLContext()</tt>).
223 * If that fails, continue to the next step.
224 * <li> Use the object factories specified in
225 * the <tt>Context.OBJECT_FACTORIES</tt> property of the environment,
226 * and of the provider resource file associated with
227 * <tt>nameCtx</tt>, in that order.
228 * The value of this property is a colon-separated list of factory
229 * class names that are tried in order, and the first one that succeeds
230 * in creating an object is the one used.
231 * If none of the factories can be loaded,
232 * return <code>refInfo</code>.
233 * If an exception is encountered while creating the object, the
234 * exception is passed up to the caller.
235 *</ol>
236 *<p>
237 * Service providers that implement the <tt>DirContext</tt>
238 * interface should use
239 * <tt>DirectoryManager.getObjectInstance()</tt>, not this method.
240 * Service providers that implement only the <tt>Context</tt>
241 * interface should use this method.
242 * <p>
243 * Note that an object factory (an object that implements the ObjectFactory
244 * interface) must be public and must have a public constructor that
245 * accepts no arguments.
246 * <p>
247 * The <code>name</code> and <code>nameCtx</code> parameters may
248 * optionally be used to specify the name of the object being created.
249 * <code>name</code> is the name of the object, relative to context
250 * <code>nameCtx</code>. This information could be useful to the object
251 * factory or to the object implementation.
252 * If there are several possible contexts from which the object
253 * could be named -- as will often be the case -- it is up to
254 * the caller to select one. A good rule of thumb is to select the
255 * "deepest" context available.
256 * If <code>nameCtx</code> is null, <code>name</code> is relative
257 * to the default initial context. If no name is being specified, the
258 * <code>name</code> parameter should be null.
259 *
260 * @param refInfo The possibly null object for which to create an object.
261 * @param name The name of this object relative to <code>nameCtx</code>.
262 * Specifying a name is optional; if it is
263 * omitted, <code>name</code> should be null.
264 * @param nameCtx The context relative to which the <code>name</code>
265 * parameter is specified. If null, <code>name</code> is
266 * relative to the default initial context.
267 * @param environment The possibly null environment to
268 * be used in the creation of the object factory and the object.
269 * @return An object created using <code>refInfo</code>; or
270 * <code>refInfo</code> if an object cannot be created using
271 * the algorithm described above.
272 * @exception NamingException if a naming exception was encountered
273 * while attempting to get a URL context, or if one of the
274 * factories accessed throws a NamingException.
275 * @exception Exception if one of the factories accessed throws an
276 * exception, or if an error was encountered while loading
277 * and instantiating the factory and object classes.
278 * A factory should only throw an exception if it does not want
279 * other factories to be used in an attempt to create an object.
280 * See ObjectFactory.getObjectInstance().
281 * @see #getURLContext
282 * @see ObjectFactory
283 * @see ObjectFactory#getObjectInstance
284 */
285 public static Object
286 getObjectInstance(Object refInfo, Name name, Context nameCtx,
287 Hashtable<?,?> environment)
288 throws Exception
289 {
290
387 // If refInfo is an array of URL strings,
388 // try to find a context factory for any one of its URLs.
389 // If no context found, continue to try object factories.
390 if (refInfo instanceof String[]) {
391 String[] urls = (String[])refInfo;
392 for (int i = 0; i <urls.length; i++) {
393 String scheme = getURLScheme(urls[i]);
394 if (scheme != null) {
395 answer = getURLObject(scheme, refInfo, name, nameCtx,
396 environment);
397 if (answer != null)
398 return answer;
399 }
400 }
401 }
402 return null;
403 }
404
405
406 /**
407 * Retrieves a context identified by <code>obj</code>, using the specified
408 * environment.
409 * Used by ContinuationContext.
410 *
411 * @param obj The object identifying the context.
412 * @param name The name of the context being returned, relative to
413 * <code>nameCtx</code>, or null if no name is being
414 * specified.
415 * See the <code>getObjectInstance</code> method for
416 * details.
417 * @param nameCtx The context relative to which <code>name</code> is
418 * specified, or null for the default initial context.
419 * See the <code>getObjectInstance</code> method for
420 * details.
421 * @param environment Environment specifying characteristics of the
422 * resulting context.
423 * @return A context identified by <code>obj</code>.
424 *
425 * @see #getObjectInstance
426 */
427 static Context getContext(Object obj, Name name, Context nameCtx,
428 Hashtable<?,?> environment) throws NamingException {
429 Object answer;
430
431 if (obj instanceof Context) {
432 // %%% Ignore environment for now. OK since method not public.
433 return (Context)obj;
434 }
435
436 try {
437 answer = getObjectInstance(obj, name, nameCtx, environment);
438 } catch (NamingException e) {
439 throw e;
440 } catch (Exception e) {
441 NamingException ne = new NamingException();
442 ne.setRootCause(e);
443 throw ne;
463 } catch (NamingException e) {
464 throw e;
465 } catch (Exception e) {
466 NamingException ne = new NamingException();
467 ne.setRootCause(e);
468 throw ne;
469 }
470
471 return (answer instanceof Resolver)
472 ? (Resolver)answer
473 : null;
474 }
475
476
477 /***************** URL Context implementations ***************/
478
479 /**
480 * Creates a context for the given URL scheme id.
481 * <p>
482 * The resulting context is for resolving URLs of the
483 * scheme <code>scheme</code>. The resulting context is not tied
484 * to a specific URL. It is able to handle arbitrary URLs with
485 * the specified scheme.
486 *<p>
487 * The class name of the factory that creates the resulting context
488 * has the naming convention <i>scheme-id</i>URLContextFactory
489 * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
490 * in the package specified as follows.
491 * The <tt>Context.URL_PKG_PREFIXES</tt> environment property (which
492 * may contain values taken from system properties,
493 * or application resource files)
494 * contains a colon-separated list of package prefixes.
495 * Each package prefix in
496 * the property is tried in the order specified to load the factory class.
497 * The default package prefix is "com.sun.jndi.url" (if none of the
498 * specified packages work, this default is tried).
499 * The complete package name is constructed using the package prefix,
500 * concatenated with the scheme id.
501 *<p>
502 * For example, if the scheme id is "ldap", and the
503 * <tt>Context.URL_PKG_PREFIXES</tt> property
504 * contains "com.widget:com.wiz.jndi",
505 * the naming manager would attempt to load the following classes
506 * until one is successfully instantiated:
507 *<ul>
508 * <li>com.widget.ldap.ldapURLContextFactory
509 * <li>com.wiz.jndi.ldap.ldapURLContextFactory
510 * <li>com.sun.jndi.url.ldap.ldapURLContextFactory
511 *</ul>
512 * If none of the package prefixes work, null is returned.
513 *<p>
514 * If a factory is instantiated, it is invoked with the following
515 * parameters to produce the resulting context.
516 * <p>
517 * <code>factory.getObjectInstance(null, environment);</code>
518 * <p>
519 * For example, invoking getObjectInstance() as shown above
520 * on a LDAP URL context factory would return a
521 * context that can resolve LDAP urls
522 * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
523 * "ldap://ldap.umich.edu/o=umich,c=us", ...).
524 *<p>
525 * Note that an object factory (an object that implements the ObjectFactory
526 * interface) must be public and must have a public constructor that
527 * accepts no arguments.
528 *
529 * @param scheme The non-null scheme-id of the URLs supported by the context.
530 * @param environment The possibly null environment properties to be
531 * used in the creation of the object factory and the context.
532 * @return A context for resolving URLs with the
533 * scheme id <code>scheme</code>;
534 * <code>null</code> if the factory for creating the
535 * context is not found.
536 * @exception NamingException If a naming exception occurs while creating
537 * the context.
538 * @see #getObjectInstance
539 * @see ObjectFactory#getObjectInstance
540 */
541 public static Context getURLContext(String scheme,
542 Hashtable<?,?> environment)
543 throws NamingException
544 {
545 // pass in 'null' to indicate creation of generic context for scheme
546 // (i.e. not specific to a URL).
547
548 Object answer = getURLObject(scheme, null, null, null, environment);
549 if (answer instanceof Context) {
550 return (Context)answer;
551 } else {
552 return null;
553 }
554 }
558 /**
559 * Creates an object for the given URL scheme id using
560 * the supplied urlInfo.
561 * <p>
562 * If urlInfo is null, the result is a context for resolving URLs
563 * with the scheme id 'scheme'.
564 * If urlInfo is a URL, the result is a context named by the URL.
565 * Names passed to this context is assumed to be relative to this
566 * context (i.e. not a URL). For example, if urlInfo is
567 * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
568 * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
569 * Subsequent names that can be passed to this context will be
570 * LDAP names relative to this context (e.g. cn="Barbs Jensen").
571 * If urlInfo is an array of URLs, the URLs are assumed
572 * to be equivalent in terms of the context to which they refer.
573 * The resulting context is like that of the single URL case.
574 * If urlInfo is of any other type, that is handled by the
575 * context factory for the URL scheme.
576 * @param scheme the URL scheme id for the context
577 * @param urlInfo information used to create the context
578 * @param name name of this object relative to <code>nameCtx</code>
579 * @param nameCtx Context whose provider resource file will be searched
580 * for package prefix values (or null if none)
581 * @param environment Environment properties for creating the context
582 * @see javax.naming.InitialContext
583 */
584 private static Object getURLObject(String scheme, Object urlInfo,
585 Name name, Context nameCtx,
586 Hashtable<?,?> environment)
587 throws NamingException {
588
589 // e.g. "ftpURLContextFactory"
590 ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
591 Context.URL_PKG_PREFIXES, environment, nameCtx,
592 "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
593
594 if (factory == null)
595 return null;
596
597 // Found object factory
598 try {
613
614 /**
615 * Use this method for accessing initctx_factory_builder while
616 * inside an unsynchronized method.
617 */
618 private static synchronized InitialContextFactoryBuilder
619 getInitialContextFactoryBuilder() {
620 return initctx_factory_builder;
621 }
622
623 /**
624 * Creates an initial context using the specified environment
625 * properties.
626 * <p>
627 * This is done as follows:
628 * <ul>
629 * <li>If an InitialContextFactoryBuilder has been installed,
630 * it is used to create the factory for creating the initial
631 * context</li>
632 * <li>Otherwise, the class specified in the
633 * <tt>Context.INITIAL_CONTEXT_FACTORY</tt> environment property
634 * is used
635 * <ul>
636 * <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader}
637 * mechanism tries to locate an {@code InitialContextFactory}
638 * provider using the current thread's context class loader</li>
639 * <li>Failing that, this implementation tries to locate a suitable
640 * {@code InitialContextFactory} using a built-in mechanism
641 * <br>
642 * (Note that an initial context factory (an object that implements
643 * the InitialContextFactory interface) must be public and must have
644 * a public constructor that accepts no arguments)</li>
645 * </ul>
646 * </li>
647 * </ul>
648 * @param env The possibly null environment properties used when
649 * creating the context.
650 * @return A non-null initial context.
651 * @exception NoInitialContextException If the
652 * <tt>Context.INITIAL_CONTEXT_FACTORY</tt> property
653 * is not found or names a nonexistent
654 * class or a class that cannot be instantiated,
655 * or if the initial context could not be created for some other
656 * reason.
657 * @exception NamingException If some other naming exception was encountered.
658 * @see javax.naming.InitialContext
659 * @see javax.naming.directory.InitialDirContext
660 */
661 public static Context getInitialContext(Hashtable<?,?> env)
662 throws NamingException {
663 InitialContextFactory factory = null;
664
665 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
666 if (builder == null) {
667 // No builder installed, use property
668 // Get initial context factory class name
669
670 String className = env != null ?
671 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
672 if (className == null) {
747 security.checkSetFactory();
748 }
749 initctx_factory_builder = builder;
750 }
751
752 /**
753 * Determines whether an initial context factory builder has
754 * been set.
755 * @return true if an initial context factory builder has
756 * been set; false otherwise.
757 * @see #setInitialContextFactoryBuilder
758 */
759 public static boolean hasInitialContextFactoryBuilder() {
760 return (getInitialContextFactoryBuilder() != null);
761 }
762
763 // ----- Continuation Context Stuff
764
765 /**
766 * Constant that holds the name of the environment property into
767 * which <tt>getContinuationContext()</tt> stores the value of its
768 * <tt>CannotProceedException</tt> parameter.
769 * This property is inherited by the continuation context, and may
770 * be used by that context's service provider to inspect the
771 * fields of the exception.
772 *<p>
773 * The value of this constant is "java.naming.spi.CannotProceedException".
774 *
775 * @see #getContinuationContext
776 * @since 1.3
777 */
778 public static final String CPE = "java.naming.spi.CannotProceedException";
779
780 /**
781 * Creates a context in which to continue a context operation.
782 *<p>
783 * In performing an operation on a name that spans multiple
784 * namespaces, a context from one naming system may need to pass
785 * the operation on to the next naming system. The context
786 * implementation does this by first constructing a
787 * <code>CannotProceedException</code> containing information
788 * pinpointing how far it has proceeded. It then obtains a
789 * continuation context from JNDI by calling
790 * <code>getContinuationContext</code>. The context
791 * implementation should then resume the context operation by
792 * invoking the same operation on the continuation context, using
793 * the remainder of the name that has not yet been resolved.
794 *<p>
795 * Before making use of the <tt>cpe</tt> parameter, this method
796 * updates the environment associated with that object by setting
797 * the value of the property <a href="#CPE"><tt>CPE</tt></a>
798 * to <tt>cpe</tt>. This property will be inherited by the
799 * continuation context, and may be used by that context's
800 * service provider to inspect the fields of this exception.
801 *
802 * @param cpe
803 * The non-null exception that triggered this continuation.
804 * @return A non-null Context object for continuing the operation.
805 * @exception NamingException If a naming exception occurred.
806 */
807 @SuppressWarnings("unchecked")
808 public static Context getContinuationContext(CannotProceedException cpe)
809 throws NamingException {
810
811 Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment();
812 if (env == null) {
813 env = new Hashtable<>(7);
814 } else {
815 // Make a (shallow) copy of the environment.
816 env = (Hashtable<Object,Object>)env.clone();
817 }
818 env.put(CPE, cpe);
819
820 ContinuationContext cctx = new ContinuationContext(cpe, env);
821 return cctx.getTargetContext();
822 }
823
824 // ------------ State Factory Stuff
825
826 /**
827 * Retrieves the state of an object for binding.
828 * <p>
829 * Service providers that implement the <tt>DirContext</tt> interface
830 * should use <tt>DirectoryManager.getStateToBind()</tt>, not this method.
831 * Service providers that implement only the <tt>Context</tt> interface
832 * should use this method.
833 *<p>
834 * This method uses the specified state factories in
835 * the <tt>Context.STATE_FACTORIES</tt> property from the environment
836 * properties, and from the provider resource file associated with
837 * <tt>nameCtx</tt>, in that order.
838 * The value of this property is a colon-separated list of factory
839 * class names that are tried in order, and the first one that succeeds
840 * in returning the object's state is the one used.
841 * If no object's state can be retrieved in this way, return the
842 * object itself.
843 * If an exception is encountered while retrieving the state, the
844 * exception is passed up to the caller.
845 * <p>
846 * Note that a state factory
847 * (an object that implements the StateFactory
848 * interface) must be public and must have a public constructor that
849 * accepts no arguments.
850 * <p>
851 * The <code>name</code> and <code>nameCtx</code> parameters may
852 * optionally be used to specify the name of the object being created.
853 * See the description of "Name and Context Parameters" in
854 * {@link ObjectFactory#getObjectInstance
855 * ObjectFactory.getObjectInstance()}
856 * for details.
857 * <p>
858 * This method may return a <tt>Referenceable</tt> object. The
859 * service provider obtaining this object may choose to store it
860 * directly, or to extract its reference (using
861 * <tt>Referenceable.getReference()</tt>) and store that instead.
862 *
863 * @param obj The non-null object for which to get state to bind.
864 * @param name The name of this object relative to <code>nameCtx</code>,
865 * or null if no name is specified.
866 * @param nameCtx The context relative to which the <code>name</code>
867 * parameter is specified, or null if <code>name</code> is
868 * relative to the default initial context.
869 * @param environment The possibly null environment to
870 * be used in the creation of the state factory and
871 * the object's state.
872 * @return The non-null object representing <tt>obj</tt>'s state for
873 * binding. It could be the object (<tt>obj</tt>) itself.
874 * @exception NamingException If one of the factories accessed throws an
875 * exception, or if an error was encountered while loading
876 * and instantiating the factory and object classes.
877 * A factory should only throw an exception if it does not want
878 * other factories to be used in an attempt to create an object.
879 * See <tt>StateFactory.getStateToBind()</tt>.
880 * @see StateFactory
881 * @see StateFactory#getStateToBind
882 * @see DirectoryManager#getStateToBind
883 * @since 1.3
884 */
885 public static Object
886 getStateToBind(Object obj, Name name, Context nameCtx,
887 Hashtable<?,?> environment)
888 throws NamingException
889 {
890
891 FactoryEnumeration factories = ResourceManager.getFactories(
892 Context.STATE_FACTORIES, environment, nameCtx);
893
894 if (factories == null) {
895 return obj;
896 }
897
898 // Try each factory until one succeeds
899 StateFactory factory;
|
32 import com.sun.naming.internal.VersionHelper;
33 import com.sun.naming.internal.ResourceManager;
34 import com.sun.naming.internal.FactoryEnumeration;
35
36 /**
37 * This class contains methods for creating context objects
38 * and objects referred to by location information in the naming
39 * or directory service.
40 *<p>
41 * This class cannot be instantiated. It has only static methods.
42 *<p>
43 * The mention of URL in the documentation for this class refers to
44 * a URL string as defined by RFC 1738 and its related RFCs. It is
45 * any string that conforms to the syntax described therein, and
46 * may not always have corresponding support in the java.net.URL
47 * class or Web browsers.
48 *<p>
49 * NamingManager is safe for concurrent access by multiple threads.
50 *<p>
51 * Except as otherwise noted,
52 * a {@code Name} or environment parameter
53 * passed to any method is owned by the caller.
54 * The implementation will not modify the object or keep a reference
55 * to it, although it may keep a reference to a clone or copy.
56 *
57 * @author Rosanna Lee
58 * @author Scott Seligman
59 * @since 1.3
60 */
61
62 public class NamingManager {
63
64 /*
65 * Disallow anyone from creating one of these.
66 * Made package private so that DirectoryManager can subclass.
67 */
68
69 NamingManager() {}
70
71 // should be protected and package private
72 static final VersionHelper helper = VersionHelper.getVersionHelper();
147 // e.printStackTrace();
148 }
149 // All other exceptions are passed up.
150
151 // Not in class path; try to use codebase
152 String codebase;
153 if (clas == null &&
154 (codebase = ref.getFactoryClassLocation()) != null) {
155 try {
156 clas = helper.loadClass(factoryName, codebase);
157 } catch (ClassNotFoundException e) {
158 }
159 }
160
161 return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
162 }
163
164
165 /**
166 * Creates an object using the factories specified in the
167 * {@code Context.OBJECT_FACTORIES} property of the environment
168 * or of the provider resource file associated with {@code nameCtx}.
169 *
170 * @return factory created; null if cannot create
171 */
172 private static Object createObjectFromFactories(Object obj, Name name,
173 Context nameCtx, Hashtable<?,?> environment) throws Exception {
174
175 FactoryEnumeration factories = ResourceManager.getFactories(
176 Context.OBJECT_FACTORIES, environment, nameCtx);
177
178 if (factories == null)
179 return null;
180
181 // Try each factory until one succeeds
182 ObjectFactory factory;
183 Object answer = null;
184 while (answer == null && factories.hasMore()) {
185 factory = (ObjectFactory)factories.next();
186 answer = factory.getObjectInstance(obj, name, nameCtx, environment);
187 }
188 return answer;
189 }
190
191 private static String getURLScheme(String str) {
192 int colon_posn = str.indexOf(':');
193 int slash_posn = str.indexOf('/');
194
195 if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
196 return str.substring(0, colon_posn);
197 return null;
198 }
199
200 /**
201 * Creates an instance of an object for the specified object
202 * and environment.
203 * <p>
204 * If an object factory builder has been installed, it is used to
205 * create a factory for creating the object.
206 * Otherwise, the following rules are used to create the object:
207 *<ol>
208 * <li>If {@code refInfo} is a {@code Reference}
209 * or {@code Referenceable} containing a factory class name,
210 * use the named factory to create the object.
211 * Return {@code refInfo} if the factory cannot be created.
212 * Under JDK 1.1, if the factory class must be loaded from a location
213 * specified in the reference, a {@code SecurityManager} must have
214 * been installed or the factory creation will fail.
215 * If an exception is encountered while creating the factory,
216 * it is passed up to the caller.
217 * <li>If {@code refInfo} is a {@code Reference} or
218 * {@code Referenceable} with no factory class name,
219 * and the address or addresses are {@code StringRefAddr}s with
220 * address type "URL",
221 * try the URL context factory corresponding to each URL's scheme id
222 * to create the object (see {@code getURLContext()}).
223 * If that fails, continue to the next step.
224 * <li> Use the object factories specified in
225 * the {@code Context.OBJECT_FACTORIES} property of the environment,
226 * and of the provider resource file associated with
227 * {@code nameCtx}, in that order.
228 * The value of this property is a colon-separated list of factory
229 * class names that are tried in order, and the first one that succeeds
230 * in creating an object is the one used.
231 * If none of the factories can be loaded,
232 * return {@code refInfo}.
233 * If an exception is encountered while creating the object, the
234 * exception is passed up to the caller.
235 *</ol>
236 *<p>
237 * Service providers that implement the {@code DirContext}
238 * interface should use
239 * {@code DirectoryManager.getObjectInstance()}, not this method.
240 * Service providers that implement only the {@code Context}
241 * interface should use this method.
242 * <p>
243 * Note that an object factory (an object that implements the ObjectFactory
244 * interface) must be public and must have a public constructor that
245 * accepts no arguments.
246 * <p>
247 * The {@code name} and {@code nameCtx} parameters may
248 * optionally be used to specify the name of the object being created.
249 * {@code name} is the name of the object, relative to context
250 * {@code nameCtx}. This information could be useful to the object
251 * factory or to the object implementation.
252 * If there are several possible contexts from which the object
253 * could be named -- as will often be the case -- it is up to
254 * the caller to select one. A good rule of thumb is to select the
255 * "deepest" context available.
256 * If {@code nameCtx} is null, {@code name} is relative
257 * to the default initial context. If no name is being specified, the
258 * {@code name} parameter should be null.
259 *
260 * @param refInfo The possibly null object for which to create an object.
261 * @param name The name of this object relative to {@code nameCtx}.
262 * Specifying a name is optional; if it is
263 * omitted, {@code name} should be null.
264 * @param nameCtx The context relative to which the {@code name}
265 * parameter is specified. If null, {@code name} is
266 * relative to the default initial context.
267 * @param environment The possibly null environment to
268 * be used in the creation of the object factory and the object.
269 * @return An object created using {@code refInfo}; or
270 * {@code refInfo} if an object cannot be created using
271 * the algorithm described above.
272 * @exception NamingException if a naming exception was encountered
273 * while attempting to get a URL context, or if one of the
274 * factories accessed throws a NamingException.
275 * @exception Exception if one of the factories accessed throws an
276 * exception, or if an error was encountered while loading
277 * and instantiating the factory and object classes.
278 * A factory should only throw an exception if it does not want
279 * other factories to be used in an attempt to create an object.
280 * See ObjectFactory.getObjectInstance().
281 * @see #getURLContext
282 * @see ObjectFactory
283 * @see ObjectFactory#getObjectInstance
284 */
285 public static Object
286 getObjectInstance(Object refInfo, Name name, Context nameCtx,
287 Hashtable<?,?> environment)
288 throws Exception
289 {
290
387 // If refInfo is an array of URL strings,
388 // try to find a context factory for any one of its URLs.
389 // If no context found, continue to try object factories.
390 if (refInfo instanceof String[]) {
391 String[] urls = (String[])refInfo;
392 for (int i = 0; i <urls.length; i++) {
393 String scheme = getURLScheme(urls[i]);
394 if (scheme != null) {
395 answer = getURLObject(scheme, refInfo, name, nameCtx,
396 environment);
397 if (answer != null)
398 return answer;
399 }
400 }
401 }
402 return null;
403 }
404
405
406 /**
407 * Retrieves a context identified by {@code obj}, using the specified
408 * environment.
409 * Used by ContinuationContext.
410 *
411 * @param obj The object identifying the context.
412 * @param name The name of the context being returned, relative to
413 * {@code nameCtx}, or null if no name is being
414 * specified.
415 * See the {@code getObjectInstance} method for
416 * details.
417 * @param nameCtx The context relative to which {@code name} is
418 * specified, or null for the default initial context.
419 * See the {@code getObjectInstance} method for
420 * details.
421 * @param environment Environment specifying characteristics of the
422 * resulting context.
423 * @return A context identified by {@code obj}.
424 *
425 * @see #getObjectInstance
426 */
427 static Context getContext(Object obj, Name name, Context nameCtx,
428 Hashtable<?,?> environment) throws NamingException {
429 Object answer;
430
431 if (obj instanceof Context) {
432 // %%% Ignore environment for now. OK since method not public.
433 return (Context)obj;
434 }
435
436 try {
437 answer = getObjectInstance(obj, name, nameCtx, environment);
438 } catch (NamingException e) {
439 throw e;
440 } catch (Exception e) {
441 NamingException ne = new NamingException();
442 ne.setRootCause(e);
443 throw ne;
463 } catch (NamingException e) {
464 throw e;
465 } catch (Exception e) {
466 NamingException ne = new NamingException();
467 ne.setRootCause(e);
468 throw ne;
469 }
470
471 return (answer instanceof Resolver)
472 ? (Resolver)answer
473 : null;
474 }
475
476
477 /***************** URL Context implementations ***************/
478
479 /**
480 * Creates a context for the given URL scheme id.
481 * <p>
482 * The resulting context is for resolving URLs of the
483 * scheme {@code scheme}. The resulting context is not tied
484 * to a specific URL. It is able to handle arbitrary URLs with
485 * the specified scheme.
486 *<p>
487 * The class name of the factory that creates the resulting context
488 * has the naming convention <i>scheme-id</i>URLContextFactory
489 * (e.g. "ftpURLContextFactory" for the "ftp" scheme-id),
490 * in the package specified as follows.
491 * The {@code Context.URL_PKG_PREFIXES} environment property (which
492 * may contain values taken from system properties,
493 * or application resource files)
494 * contains a colon-separated list of package prefixes.
495 * Each package prefix in
496 * the property is tried in the order specified to load the factory class.
497 * The default package prefix is "com.sun.jndi.url" (if none of the
498 * specified packages work, this default is tried).
499 * The complete package name is constructed using the package prefix,
500 * concatenated with the scheme id.
501 *<p>
502 * For example, if the scheme id is "ldap", and the
503 * {@code Context.URL_PKG_PREFIXES} property
504 * contains "com.widget:com.wiz.jndi",
505 * the naming manager would attempt to load the following classes
506 * until one is successfully instantiated:
507 *<ul>
508 * <li>com.widget.ldap.ldapURLContextFactory
509 * <li>com.wiz.jndi.ldap.ldapURLContextFactory
510 * <li>com.sun.jndi.url.ldap.ldapURLContextFactory
511 *</ul>
512 * If none of the package prefixes work, null is returned.
513 *<p>
514 * If a factory is instantiated, it is invoked with the following
515 * parameters to produce the resulting context.
516 * <p>
517 * {@code factory.getObjectInstance(null, environment);}
518 * <p>
519 * For example, invoking getObjectInstance() as shown above
520 * on a LDAP URL context factory would return a
521 * context that can resolve LDAP urls
522 * (e.g. "ldap://ldap.wiz.com/o=wiz,c=us",
523 * "ldap://ldap.umich.edu/o=umich,c=us", ...).
524 *<p>
525 * Note that an object factory (an object that implements the ObjectFactory
526 * interface) must be public and must have a public constructor that
527 * accepts no arguments.
528 *
529 * @param scheme The non-null scheme-id of the URLs supported by the context.
530 * @param environment The possibly null environment properties to be
531 * used in the creation of the object factory and the context.
532 * @return A context for resolving URLs with the
533 * scheme id {@code scheme};
534 * {@code null} if the factory for creating the
535 * context is not found.
536 * @exception NamingException If a naming exception occurs while creating
537 * the context.
538 * @see #getObjectInstance
539 * @see ObjectFactory#getObjectInstance
540 */
541 public static Context getURLContext(String scheme,
542 Hashtable<?,?> environment)
543 throws NamingException
544 {
545 // pass in 'null' to indicate creation of generic context for scheme
546 // (i.e. not specific to a URL).
547
548 Object answer = getURLObject(scheme, null, null, null, environment);
549 if (answer instanceof Context) {
550 return (Context)answer;
551 } else {
552 return null;
553 }
554 }
558 /**
559 * Creates an object for the given URL scheme id using
560 * the supplied urlInfo.
561 * <p>
562 * If urlInfo is null, the result is a context for resolving URLs
563 * with the scheme id 'scheme'.
564 * If urlInfo is a URL, the result is a context named by the URL.
565 * Names passed to this context is assumed to be relative to this
566 * context (i.e. not a URL). For example, if urlInfo is
567 * "ldap://ldap.wiz.com/o=Wiz,c=us", the resulting context will
568 * be that pointed to by "o=Wiz,c=us" on the server 'ldap.wiz.com'.
569 * Subsequent names that can be passed to this context will be
570 * LDAP names relative to this context (e.g. cn="Barbs Jensen").
571 * If urlInfo is an array of URLs, the URLs are assumed
572 * to be equivalent in terms of the context to which they refer.
573 * The resulting context is like that of the single URL case.
574 * If urlInfo is of any other type, that is handled by the
575 * context factory for the URL scheme.
576 * @param scheme the URL scheme id for the context
577 * @param urlInfo information used to create the context
578 * @param name name of this object relative to {@code nameCtx}
579 * @param nameCtx Context whose provider resource file will be searched
580 * for package prefix values (or null if none)
581 * @param environment Environment properties for creating the context
582 * @see javax.naming.InitialContext
583 */
584 private static Object getURLObject(String scheme, Object urlInfo,
585 Name name, Context nameCtx,
586 Hashtable<?,?> environment)
587 throws NamingException {
588
589 // e.g. "ftpURLContextFactory"
590 ObjectFactory factory = (ObjectFactory)ResourceManager.getFactory(
591 Context.URL_PKG_PREFIXES, environment, nameCtx,
592 "." + scheme + "." + scheme + "URLContextFactory", defaultPkgPrefix);
593
594 if (factory == null)
595 return null;
596
597 // Found object factory
598 try {
613
614 /**
615 * Use this method for accessing initctx_factory_builder while
616 * inside an unsynchronized method.
617 */
618 private static synchronized InitialContextFactoryBuilder
619 getInitialContextFactoryBuilder() {
620 return initctx_factory_builder;
621 }
622
623 /**
624 * Creates an initial context using the specified environment
625 * properties.
626 * <p>
627 * This is done as follows:
628 * <ul>
629 * <li>If an InitialContextFactoryBuilder has been installed,
630 * it is used to create the factory for creating the initial
631 * context</li>
632 * <li>Otherwise, the class specified in the
633 * {@code Context.INITIAL_CONTEXT_FACTORY} environment property
634 * is used
635 * <ul>
636 * <li>First, the {@linkplain java.util.ServiceLoader ServiceLoader}
637 * mechanism tries to locate an {@code InitialContextFactory}
638 * provider using the current thread's context class loader</li>
639 * <li>Failing that, this implementation tries to locate a suitable
640 * {@code InitialContextFactory} using a built-in mechanism
641 * <br>
642 * (Note that an initial context factory (an object that implements
643 * the InitialContextFactory interface) must be public and must have
644 * a public constructor that accepts no arguments)</li>
645 * </ul>
646 * </li>
647 * </ul>
648 * @param env The possibly null environment properties used when
649 * creating the context.
650 * @return A non-null initial context.
651 * @exception NoInitialContextException If the
652 * {@code Context.INITIAL_CONTEXT_FACTORY} property
653 * is not found or names a nonexistent
654 * class or a class that cannot be instantiated,
655 * or if the initial context could not be created for some other
656 * reason.
657 * @exception NamingException If some other naming exception was encountered.
658 * @see javax.naming.InitialContext
659 * @see javax.naming.directory.InitialDirContext
660 */
661 public static Context getInitialContext(Hashtable<?,?> env)
662 throws NamingException {
663 InitialContextFactory factory = null;
664
665 InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
666 if (builder == null) {
667 // No builder installed, use property
668 // Get initial context factory class name
669
670 String className = env != null ?
671 (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
672 if (className == null) {
747 security.checkSetFactory();
748 }
749 initctx_factory_builder = builder;
750 }
751
752 /**
753 * Determines whether an initial context factory builder has
754 * been set.
755 * @return true if an initial context factory builder has
756 * been set; false otherwise.
757 * @see #setInitialContextFactoryBuilder
758 */
759 public static boolean hasInitialContextFactoryBuilder() {
760 return (getInitialContextFactoryBuilder() != null);
761 }
762
763 // ----- Continuation Context Stuff
764
765 /**
766 * Constant that holds the name of the environment property into
767 * which {@code getContinuationContext()} stores the value of its
768 * {@code CannotProceedException} parameter.
769 * This property is inherited by the continuation context, and may
770 * be used by that context's service provider to inspect the
771 * fields of the exception.
772 *<p>
773 * The value of this constant is "java.naming.spi.CannotProceedException".
774 *
775 * @see #getContinuationContext
776 * @since 1.3
777 */
778 public static final String CPE = "java.naming.spi.CannotProceedException";
779
780 /**
781 * Creates a context in which to continue a context operation.
782 *<p>
783 * In performing an operation on a name that spans multiple
784 * namespaces, a context from one naming system may need to pass
785 * the operation on to the next naming system. The context
786 * implementation does this by first constructing a
787 * {@code CannotProceedException} containing information
788 * pinpointing how far it has proceeded. It then obtains a
789 * continuation context from JNDI by calling
790 * {@code getContinuationContext}. The context
791 * implementation should then resume the context operation by
792 * invoking the same operation on the continuation context, using
793 * the remainder of the name that has not yet been resolved.
794 *<p>
795 * Before making use of the {@code cpe} parameter, this method
796 * updates the environment associated with that object by setting
797 * the value of the property <a href="#CPE">{@code CPE}</a>
798 * to {@code cpe}. This property will be inherited by the
799 * continuation context, and may be used by that context's
800 * service provider to inspect the fields of this exception.
801 *
802 * @param cpe
803 * The non-null exception that triggered this continuation.
804 * @return A non-null Context object for continuing the operation.
805 * @exception NamingException If a naming exception occurred.
806 */
807 @SuppressWarnings("unchecked")
808 public static Context getContinuationContext(CannotProceedException cpe)
809 throws NamingException {
810
811 Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment();
812 if (env == null) {
813 env = new Hashtable<>(7);
814 } else {
815 // Make a (shallow) copy of the environment.
816 env = (Hashtable<Object,Object>)env.clone();
817 }
818 env.put(CPE, cpe);
819
820 ContinuationContext cctx = new ContinuationContext(cpe, env);
821 return cctx.getTargetContext();
822 }
823
824 // ------------ State Factory Stuff
825
826 /**
827 * Retrieves the state of an object for binding.
828 * <p>
829 * Service providers that implement the {@code DirContext} interface
830 * should use {@code DirectoryManager.getStateToBind()}, not this method.
831 * Service providers that implement only the {@code Context} interface
832 * should use this method.
833 *<p>
834 * This method uses the specified state factories in
835 * the {@code Context.STATE_FACTORIES} property from the environment
836 * properties, and from the provider resource file associated with
837 * {@code nameCtx}, in that order.
838 * The value of this property is a colon-separated list of factory
839 * class names that are tried in order, and the first one that succeeds
840 * in returning the object's state is the one used.
841 * If no object's state can be retrieved in this way, return the
842 * object itself.
843 * If an exception is encountered while retrieving the state, the
844 * exception is passed up to the caller.
845 * <p>
846 * Note that a state factory
847 * (an object that implements the StateFactory
848 * interface) must be public and must have a public constructor that
849 * accepts no arguments.
850 * <p>
851 * The {@code name} and {@code nameCtx} parameters may
852 * optionally be used to specify the name of the object being created.
853 * See the description of "Name and Context Parameters" in
854 * {@link ObjectFactory#getObjectInstance
855 * ObjectFactory.getObjectInstance()}
856 * for details.
857 * <p>
858 * This method may return a {@code Referenceable} object. The
859 * service provider obtaining this object may choose to store it
860 * directly, or to extract its reference (using
861 * {@code Referenceable.getReference()}) and store that instead.
862 *
863 * @param obj The non-null object for which to get state to bind.
864 * @param name The name of this object relative to {@code nameCtx},
865 * or null if no name is specified.
866 * @param nameCtx The context relative to which the {@code name}
867 * parameter is specified, or null if {@code name} is
868 * relative to the default initial context.
869 * @param environment The possibly null environment to
870 * be used in the creation of the state factory and
871 * the object's state.
872 * @return The non-null object representing {@code obj}'s state for
873 * binding. It could be the object ({@code obj}) itself.
874 * @exception NamingException If one of the factories accessed throws an
875 * exception, or if an error was encountered while loading
876 * and instantiating the factory and object classes.
877 * A factory should only throw an exception if it does not want
878 * other factories to be used in an attempt to create an object.
879 * See {@code StateFactory.getStateToBind()}.
880 * @see StateFactory
881 * @see StateFactory#getStateToBind
882 * @see DirectoryManager#getStateToBind
883 * @since 1.3
884 */
885 public static Object
886 getStateToBind(Object obj, Name name, Context nameCtx,
887 Hashtable<?,?> environment)
888 throws NamingException
889 {
890
891 FactoryEnumeration factories = ResourceManager.getFactories(
892 Context.STATE_FACTORIES, environment, nameCtx);
893
894 if (factories == null) {
895 return obj;
896 }
897
898 // Try each factory until one succeeds
899 StateFactory factory;
|