1 /*
2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 *
5 *
6 *
7 *
8 *
9 *
10 *
11 *
12 *
13 *
14 *
15 *
16 *
17 *
18 *
19 *
20 *
21 *
22 *
23 *
24 */
25
26 package javax.naming;
27
28 import java.util.Hashtable;
29 import javax.naming.spi.NamingManager;
30 import com.sun.naming.internal.ResourceManager;
31
32 /**
33 * This class is the starting context for performing naming operations.
34 *<p>
35 * All naming operations are relative to a context.
36 * The initial context implements the Context interface and
37 * provides the starting point for resolution of names.
38 *<p>
39 * <a name=ENVIRONMENT></a>
40 * When the initial context is constructed, its environment
41 * is initialized with properties defined in the environment parameter
42 * passed to the constructor, and in any
43 * <a href=Context.html#RESOURCEFILES>application resource files</a>.
44 * In addition, a small number of standard JNDI properties may
45 * be specified as system properties or as applet parameters
46 * (through the use of {@link Context#APPLET}).
47 * These special properties are listed in the field detail sections of the
48 * <a href=Context.html#field_detail><tt>Context</tt></a> and
49 * <a href=ldap/LdapContext.html#field_detail><tt>LdapContext</tt></a>
50 * interface documentation.
51 *<p>
52 * JNDI determines each property's value by merging
53 * the values from the following two sources, in order:
54 * <ol>
55 * <li>
56 * The first occurrence of the property from the constructor's
57 * environment parameter and (for appropriate properties) the applet
58 * parameters and system properties.
59 * <li>
60 * The application resource files (<tt>jndi.properties</tt>).
61 * </ol>
62 * For each property found in both of these two sources, or in
63 * more than one application resource file, the property's value
64 * is determined as follows. If the property is
65 * one of the standard JNDI properties that specify a list of JNDI
66 * factories (see <a href=Context.html#LISTPROPS><tt>Context</tt></a>),
67 * all of the values are
68 * concatenated into a single colon-separated list. For other
69 * properties, only the first value found is used.
70 *
71 *<p>
72 * The initial context implementation is determined at runtime.
73 * The default policy uses the environment property
74 * "{@link Context#INITIAL_CONTEXT_FACTORY java.naming.factory.initial}",
75 * which contains the class name of the initial context factory.
76 * An exception to this policy is made when resolving URL strings, as described
77 * below.
78 *<p>
79 * When a URL string (a <tt>String</tt> of the form
80 * <em>scheme_id:rest_of_name</em>) is passed as a name parameter to
81 * any method, a URL context factory for handling that scheme is
82 * located and used to resolve the URL. If no such factory is found,
83 * the initial context specified by
84 * <tt>"java.naming.factory.initial"</tt> is used. Similarly, when a
85 * <tt>CompositeName</tt> object whose first component is a URL string is
86 * passed as a name parameter to any method, a URL context factory is
87 * located and used to resolve the first name component.
88 * See {@link NamingManager#getURLContext
89 * <tt>NamingManager.getURLContext()</tt>} for a description of how URL
90 * context factories are located.
91 *<p>
92 * This default policy of locating the initial context and URL context
93 * factories may be overridden
94 * by calling
95 * <tt>NamingManager.setInitialContextFactoryBuilder()</tt>.
96 *<p>
97 * NoInitialContextException is thrown when an initial context cannot
98 * be instantiated. This exception can be thrown during any interaction
99 * with the InitialContext, not only when the InitialContext is constructed.
100 * For example, the implementation of the initial context might lazily
101 * retrieve the context only when actual methods are invoked on it.
102 * The application should not have any dependency on when the existence
103 * of an initial context is determined.
104 *<p>
105 * When the environment property "java.naming.factory.initial" is
106 * non-null, the InitialContext constructor will attempt to create the
107 * initial context specified therein. At that time, the initial context factory
108 * involved might throw an exception if a problem is encountered. However,
109 * it is provider implementation-dependent when it verifies and indicates
110 * to the users of the initial context any environment property- or
111 * connection- related problems. It can do so lazily--delaying until
112 * an operation is performed on the context, or eagerly, at the time
113 * the context is constructed.
114 *<p>
115 * An InitialContext instance is not synchronized against concurrent
116 * access by multiple threads. Multiple threads each manipulating a
117 * different InitialContext instance need not synchronize.
118 * Threads that need to access a single InitialContext instance
119 * concurrently should synchronize amongst themselves and provide the
120 * necessary locking.
121 *
122 * @author Rosanna Lee
123 * @author Scott Seligman
124 *
125 * @see Context
126 * @see NamingManager#setInitialContextFactoryBuilder
127 * NamingManager.setInitialContextFactoryBuilder
128 * @since JNDI 1.1 / Java 2 Platform, Standard Edition, v 1.3
129 */
130
131 public class InitialContext implements Context {
132
133 /**
134 * The environment associated with this InitialContext.
135 * It is initialized to null and is updated by the constructor
136 * that accepts an environment or by the <tt>init()</tt> method.
137 * @see #addToEnvironment
138 * @see #removeFromEnvironment
139 * @see #getEnvironment
140 */
141 protected Hashtable<Object,Object> myProps = null;
142
143 /**
144 * Field holding the result of calling NamingManager.getInitialContext().
145 * It is set by getDefaultInitCtx() the first time getDefaultInitCtx()
146 * is called. Subsequent invocations of getDefaultInitCtx() return
147 * the value of defaultInitCtx.
148 * @see #getDefaultInitCtx
149 */
150 protected Context defaultInitCtx = null;
151
152 /**
153 * Field indicating whether the initial context has been obtained
154 * by calling NamingManager.getInitialContext().
155 * If true, its result is in <code>defaultInitCtx</code>.
156 */
157 protected boolean gotDefault = false;
158
159 /**
160 * Constructs an initial context with the option of not
161 * initializing it. This may be used by a constructor in
162 * a subclass when the value of the environment parameter
163 * is not yet known at the time the <tt>InitialContext</tt>
164 * constructor is called. The subclass's constructor will
165 * call this constructor, compute the value of the environment,
166 * and then call <tt>init()</tt> before returning.
167 *
168 * @param lazy
169 * true means do not initialize the initial context; false
170 * is equivalent to calling <tt>new InitialContext()</tt>
171 * @throws NamingException if a naming exception is encountered
172 *
173 * @see #init(Hashtable)
174 * @since 1.3
175 */
176 protected InitialContext(boolean lazy) throws NamingException {
177 if (!lazy) {
178 init(null);
179 }
180 }
181
182 /**
183 * Constructs an initial context.
184 * No environment properties are supplied.
185 * Equivalent to <tt>new InitialContext(null)</tt>.
186 *
187 * @throws NamingException if a naming exception is encountered
188 *
189 * @see #InitialContext(Hashtable)
190 */
191 public InitialContext() throws NamingException {
192 init(null);
193 }
194
195 /**
196 * Constructs an initial context using the supplied environment.
197 * Environment properties are discussed in the class description.
198 *
199 * <p> This constructor will not modify <tt>environment</tt>
200 * or save a reference to it, but may save a clone.
201 * Caller should not modify mutable keys and values in
202 * <tt>environment</tt> after it has been passed to the constructor.
203 *
204 * @param environment
205 * environment used to create the initial context.
206 * Null indicates an empty environment.
207 *
208 * @throws NamingException if a naming exception is encountered
209 */
210 public InitialContext(Hashtable<?,?> environment)
211 throws NamingException
212 {
213 if (environment != null) {
214 environment = (Hashtable)environment.clone();
215 }
216 init(environment);
217 }
218
219 /**
220 * Initializes the initial context using the supplied environment.
221 * Environment properties are discussed in the class description.
222 *
223 * <p> This method will modify <tt>environment</tt> and save
224 * a reference to it. The caller may no longer modify it.
225 *
226 * @param environment
227 * environment used to create the initial context.
228 * Null indicates an empty environment.
229 *
230 * @throws NamingException if a naming exception is encountered
231 *
232 * @see #InitialContext(boolean)
233 * @since 1.3
234 */
235 @SuppressWarnings("unchecked")
236 protected void init(Hashtable<?,?> environment)
237 throws NamingException
238 {
239 myProps = (Hashtable<Object,Object>)
240 ResourceManager.getInitialEnvironment(environment);
241
242 if (myProps.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
243 // user has specified initial context factory; try to get it
244 getDefaultInitCtx();
245 }
246 }
247
248 /**
249 * A static method to retrieve the named object.
250 * This is a shortcut method equivalent to invoking:
251 * <p>
252 * <code>
253 * InitialContext ic = new InitialContext();
254 * Object obj = ic.lookup();
255 * </code>
256 * <p> If <tt>name</tt> is empty, returns a new instance of this context
257 * (which represents the same naming context as this context, but its
258 * environment may be modified independently and it may be accessed
259 * concurrently).
260 *
261 * @param <T> the type of the returned object
262 * @param name
263 * the name of the object to look up
264 * @return the object bound to <tt>name</tt>
265 * @throws NamingException if a naming exception is encountered
266 *
267 * @see #doLookup(String)
268 * @see #lookup(Name)
269 * @since 1.6
270 */
271 @SuppressWarnings("unchecked")
272 public static <T> T doLookup(Name name)
273 throws NamingException {
274 return (T) (new InitialContext()).lookup(name);
275 }
276
277 /**
278 * A static method to retrieve the named object.
279 * See {@link #doLookup(Name)} for details.
280 * @param <T> the type of the returned object
281 * @param name
282 * the name of the object to look up
283 * @return the object bound to <tt>name</tt>
284 * @throws NamingException if a naming exception is encountered
285 * @since 1.6
286 */
287 @SuppressWarnings("unchecked")
288 public static <T> T doLookup(String name)
289 throws NamingException {
290 return (T) (new InitialContext()).lookup(name);
291 }
292
293 private static String getURLScheme(String str) {
294 int colon_posn = str.indexOf(':');
295 int slash_posn = str.indexOf('/');
296
297 if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
298 return str.substring(0, colon_posn);
299 return null;
300 }
301
302 /**
303 * Retrieves the initial context by calling
304 * <code>NamingManager.getInitialContext()</code>
305 * and cache it in defaultInitCtx.
306 * Set <code>gotDefault</code> so that we know we've tried this before.
307 * @return The non-null cached initial context.
308 * @exception NoInitialContextException If cannot find an initial context.
309 * @exception NamingException If a naming exception was encountered.
310 */
311 protected Context getDefaultInitCtx() throws NamingException{
312 if (!gotDefault) {
313 defaultInitCtx = NamingManager.getInitialContext(myProps);
314 gotDefault = true;
315 }
316 if (defaultInitCtx == null)
317 throw new NoInitialContextException();
318
319 return defaultInitCtx;
320 }
321
322 /**
323 * Retrieves a context for resolving the string name <code>name</code>.
324 * If <code>name</code> name is a URL string, then attempt
325 * to find a URL context for it. If none is found, or if
326 * <code>name</code> is not a URL string, then return
327 * <code>getDefaultInitCtx()</code>.
328 *<p>
329 * See getURLOrDefaultInitCtx(Name) for description
330 * of how a subclass should use this method.
331 * @param name The non-null name for which to get the context.
332 * @return A URL context for <code>name</code> or the cached
333 * initial context. The result cannot be null.
334 * @exception NoInitialContextException If cannot find an initial context.
335 * @exception NamingException In a naming exception is encountered.
336 * @see javax.naming.spi.NamingManager#getURLContext
337 */
338 protected Context getURLOrDefaultInitCtx(String name)
339 throws NamingException {
340 if (NamingManager.hasInitialContextFactoryBuilder()) {
341 return getDefaultInitCtx();
342 }
343 String scheme = getURLScheme(name);
344 if (scheme != null) {
345 Context ctx = NamingManager.getURLContext(scheme, myProps);
346 if (ctx != null) {
347 return ctx;
348 }
349 }
350 return getDefaultInitCtx();
351 }
352
353 /**
354 * Retrieves a context for resolving <code>name</code>.
355 * If the first component of <code>name</code> name is a URL string,
356 * then attempt to find a URL context for it. If none is found, or if
357 * the first component of <code>name</code> is not a URL string,
358 * then return <code>getDefaultInitCtx()</code>.
359 *<p>
360 * When creating a subclass of InitialContext, use this method as
361 * follows.
362 * Define a new method that uses this method to get an initial
363 * context of the desired subclass.
364 * <blockquote><pre>
365 * protected XXXContext getURLOrDefaultInitXXXCtx(Name name)
366 * throws NamingException {
367 * Context answer = getURLOrDefaultInitCtx(name);
368 * if (!(answer instanceof XXXContext)) {
369 * if (answer == null) {
370 * throw new NoInitialContextException();
371 * } else {
372 * throw new NotContextException("Not an XXXContext");
373 * }
374 * }
375 * return (XXXContext)answer;
376 * }
377 * </pre></blockquote>
378 * When providing implementations for the new methods in the subclass,
379 * use this newly defined method to get the initial context.
380 * <blockquote><pre>
381 * public Object XXXMethod1(Name name, ...) {
382 * throws NamingException {
383 * return getURLOrDefaultInitXXXCtx(name).XXXMethod1(name, ...);
384 * }
385 * </pre></blockquote>
386 *
387 * @param name The non-null name for which to get the context.
388 * @return A URL context for <code>name</code> or the cached
389 * initial context. The result cannot be null.
390 * @exception NoInitialContextException If cannot find an initial context.
391 * @exception NamingException In a naming exception is encountered.
392 *
393 * @see javax.naming.spi.NamingManager#getURLContext
394 */
395 protected Context getURLOrDefaultInitCtx(Name name)
396 throws NamingException {
397 if (NamingManager.hasInitialContextFactoryBuilder()) {
398 return getDefaultInitCtx();
399 }
400 if (name.size() > 0) {
401 String first = name.get(0);
402 String scheme = getURLScheme(first);
403 if (scheme != null) {
404 Context ctx = NamingManager.getURLContext(scheme, myProps);
405 if (ctx != null) {
406 return ctx;
407 }
408 }
409 }
410 return getDefaultInitCtx();
411 }
412
413 // Context methods
414 // Most Javadoc is deferred to the Context interface.
415
416 public Object lookup(String name) throws NamingException {
417 return getURLOrDefaultInitCtx(name).lookup(name);
418 }
419
420 public Object lookup(Name name) throws NamingException {
421 return getURLOrDefaultInitCtx(name).lookup(name);
422 }
423
424 public void bind(String name, Object obj) throws NamingException {
425 getURLOrDefaultInitCtx(name).bind(name, obj);
426 }
427
428 public void bind(Name name, Object obj) throws NamingException {
429 getURLOrDefaultInitCtx(name).bind(name, obj);
430 }
431
432 public void rebind(String name, Object obj) throws NamingException {
433 getURLOrDefaultInitCtx(name).rebind(name, obj);
434 }
435
436 public void rebind(Name name, Object obj) throws NamingException {
437 getURLOrDefaultInitCtx(name).rebind(name, obj);
438 }
439
440 public void unbind(String name) throws NamingException {
441 getURLOrDefaultInitCtx(name).unbind(name);
442 }
443
444 public void unbind(Name name) throws NamingException {
445 getURLOrDefaultInitCtx(name).unbind(name);
446 }
447
448 public void rename(String oldName, String newName) throws NamingException {
449 getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
450 }
451
452 public void rename(Name oldName, Name newName)
453 throws NamingException
454 {
455 getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
456 }
457
458 public NamingEnumeration<NameClassPair> list(String name)
459 throws NamingException
460 {
461 return (getURLOrDefaultInitCtx(name).list(name));
462 }
463
464 public NamingEnumeration<NameClassPair> list(Name name)
465 throws NamingException
466 {
467 return (getURLOrDefaultInitCtx(name).list(name));
468 }
469
470 public NamingEnumeration<Binding> listBindings(String name)
471 throws NamingException {
472 return getURLOrDefaultInitCtx(name).listBindings(name);
473 }
474
475 public NamingEnumeration<Binding> listBindings(Name name)
476 throws NamingException {
477 return getURLOrDefaultInitCtx(name).listBindings(name);
478 }
479
480 public void destroySubcontext(String name) throws NamingException {
481 getURLOrDefaultInitCtx(name).destroySubcontext(name);
482 }
483
484 public void destroySubcontext(Name name) throws NamingException {
485 getURLOrDefaultInitCtx(name).destroySubcontext(name);
486 }
487
488 public Context createSubcontext(String name) throws NamingException {
489 return getURLOrDefaultInitCtx(name).createSubcontext(name);
490 }
491
492 public Context createSubcontext(Name name) throws NamingException {
493 return getURLOrDefaultInitCtx(name).createSubcontext(name);
494 }
495
496 public Object lookupLink(String name) throws NamingException {
497 return getURLOrDefaultInitCtx(name).lookupLink(name);
498 }
499
500 public Object lookupLink(Name name) throws NamingException {
501 return getURLOrDefaultInitCtx(name).lookupLink(name);
502 }
503
504 public NameParser getNameParser(String name) throws NamingException {
505 return getURLOrDefaultInitCtx(name).getNameParser(name);
506 }
507
508 public NameParser getNameParser(Name name) throws NamingException {
509 return getURLOrDefaultInitCtx(name).getNameParser(name);
510 }
511
512 /**
513 * Composes the name of this context with a name relative to
514 * this context.
515 * Since an initial context may never be named relative
516 * to any context other than itself, the value of the
517 * <tt>prefix</tt> parameter must be an empty name (<tt>""</tt>).
518 */
519 public String composeName(String name, String prefix)
520 throws NamingException {
521 return name;
522 }
523
524 /**
525 * Composes the name of this context with a name relative to
526 * this context.
527 * Since an initial context may never be named relative
528 * to any context other than itself, the value of the
529 * <tt>prefix</tt> parameter must be an empty name.
530 */
531 public Name composeName(Name name, Name prefix)
532 throws NamingException
533 {
534 return (Name)name.clone();
535 }
536
537 public Object addToEnvironment(String propName, Object propVal)
538 throws NamingException {
539 myProps.put(propName, propVal);
540 return getDefaultInitCtx().addToEnvironment(propName, propVal);
541 }
542
543 public Object removeFromEnvironment(String propName)
544 throws NamingException {
545 myProps.remove(propName);
546 return getDefaultInitCtx().removeFromEnvironment(propName);
547 }
548
549 public Hashtable<?,?> getEnvironment() throws NamingException {
550 return getDefaultInitCtx().getEnvironment();
551 }
552
553 public void close() throws NamingException {
554 myProps = null;
555 if (defaultInitCtx != null) {
556 defaultInitCtx.close();
557 defaultInitCtx = null;
558 }
559 gotDefault = false;
560 }
561
562 public String getNameInNamespace() throws NamingException {
563 return getDefaultInitCtx().getNameInNamespace();
564 }
565 };
566