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