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