View Javadoc
1   /*
2    * Copyright (c) 1999, 2013, 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 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 };