001 /*
002 * Copyright 1999-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.naming;
027
028 import java.util.Hashtable;
029 import javax.naming.spi.NamingManager;
030 import com.sun.naming.internal.ResourceManager;
031
032 /**
033 * This class is the starting context for performing naming operations.
034 *<p>
035 * All naming operations are relative to a context.
036 * The initial context implements the Context interface and
037 * provides the starting point for resolution of names.
038 *<p>
039 * <a name=ENVIRONMENT></a>
040 * When the initial context is constructed, its environment
041 * is initialized with properties defined in the environment parameter
042 * passed to the constructor, and in any
043 * <a href=Context.html#RESOURCEFILES>application resource files</a>.
044 * In addition, a small number of standard JNDI properties may
045 * be specified as system properties or as applet parameters
046 * (through the use of {@link Context#APPLET}).
047 * These special properties are listed in the field detail sections of the
048 * <a href=Context.html#field_detail><tt>Context</tt></a> and
049 * <a href=ldap/LdapContext.html#field_detail><tt>LdapContext</tt></a>
050 * interface documentation.
051 *<p>
052 * JNDI determines each property's value by merging
053 * the values from the following two sources, in order:
054 * <ol>
055 * <li>
056 * The first occurrence of the property from the constructor's
057 * environment parameter and (for appropriate properties) the applet
058 * parameters and system properties.
059 * <li>
060 * The application resource files (<tt>jndi.properties</tt>).
061 * </ol>
062 * For each property found in both of these two sources, or in
063 * more than one application resource file, the property's value
064 * is determined as follows. If the property is
065 * one of the standard JNDI properties that specify a list of JNDI
066 * factories (see <a href=Context.html#LISTPROPS><tt>Context</tt></a>),
067 * all of the values are
068 * concatenated into a single colon-separated list. For other
069 * properties, only the first value found is used.
070 *
071 *<p>
072 * The initial context implementation is determined at runtime.
073 * The default policy uses the environment property
074 * "{@link Context#INITIAL_CONTEXT_FACTORY java.naming.factory.initial}",
075 * which contains the class name of the initial context factory.
076 * An exception to this policy is made when resolving URL strings, as described
077 * below.
078 *<p>
079 * When a URL string (a <tt>String</tt> of the form
080 * <em>scheme_id:rest_of_name</em>) is passed as a name parameter to
081 * any method, a URL context factory for handling that scheme is
082 * located and used to resolve the URL. If no such factory is found,
083 * the initial context specified by
084 * <tt>"java.naming.factory.initial"</tt> is used. Similarly, when a
085 * <tt>CompositeName</tt> object whose first component is a URL string is
086 * passed as a name parameter to any method, a URL context factory is
087 * located and used to resolve the first name component.
088 * See {@link NamingManager#getURLContext
089 * <tt>NamingManager.getURLContext()</tt>} for a description of how URL
090 * context factories are located.
091 *<p>
092 * This default policy of locating the initial context and URL context
093 * factories may be overridden
094 * by calling
095 * <tt>NamingManager.setInitialContextFactoryBuilder()</tt>.
096 *<p>
097 * NoInitialContextException is thrown when an initial context cannot
098 * be instantiated. This exception can be thrown during any interaction
099 * 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 * @version 1.21 07/05/05
125 *
126 * @see Context
127 * @see NamingManager#setInitialContextFactoryBuilder
128 * NamingManager.setInitialContextFactoryBuilder
129 * @since JNDI 1.1 / Java 2 Platform, Standard Edition, v 1.3
130 */
131
132 public class InitialContext implements Context {
133
134 /**
135 * The environment associated with this InitialContext.
136 * It is initialized to null and is updated by the constructor
137 * that accepts an environment or by the <tt>init()</tt> method.
138 * @see #addToEnvironment
139 * @see #removeFromEnvironment
140 * @see #getEnvironment
141 */
142 protected Hashtable<Object, Object> myProps = null;
143
144 /**
145 * Field holding the result of calling NamingManager.getInitialContext().
146 * It is set by getDefaultInitCtx() the first time getDefaultInitCtx()
147 * is called. Subsequent invocations of getDefaultInitCtx() return
148 * the value of defaultInitCtx.
149 * @see #getDefaultInitCtx
150 */
151 protected Context defaultInitCtx = null;
152
153 /**
154 * Field indicating whether the initial context has been obtained
155 * by calling NamingManager.getInitialContext().
156 * If true, its result is in <code>defaultInitCtx</code>.
157 */
158 protected boolean gotDefault = false;
159
160 /**
161 * Constructs an initial context with the option of not
162 * initializing it. This may be used by a constructor in
163 * a subclass when the value of the environment parameter
164 * is not yet known at the time the <tt>InitialContext</tt>
165 * constructor is called. The subclass's constructor will
166 * call this constructor, compute the value of the environment,
167 * and then call <tt>init()</tt> before returning.
168 *
169 * @param lazy
170 * true means do not initialize the initial context; false
171 * is equivalent to calling <tt>new InitialContext()</tt>
172 * @throws NamingException if a naming exception is encountered
173 *
174 * @see #init(Hashtable)
175 * @since 1.3
176 */
177 protected InitialContext(boolean lazy) throws NamingException {
178 if (!lazy) {
179 init(null);
180 }
181 }
182
183 /**
184 * Constructs an initial context.
185 * No environment properties are supplied.
186 * Equivalent to <tt>new InitialContext(null)</tt>.
187 *
188 * @throws NamingException if a naming exception is encountered
189 *
190 * @see #InitialContext(Hashtable)
191 */
192 public InitialContext() throws NamingException {
193 init(null);
194 }
195
196 /**
197 * Constructs an initial context using the supplied environment.
198 * Environment properties are discussed in the class description.
199 *
200 * <p> This constructor will not modify <tt>environment</tt>
201 * or save a reference to it, but may save a clone.
202 *
203 * @param environment
204 * environment used to create the initial context.
205 * Null indicates an empty environment.
206 *
207 * @throws NamingException if a naming exception is encountered
208 */
209 public InitialContext(Hashtable<?, ?> environment)
210 throws NamingException {
211 if (environment != null) {
212 environment = (Hashtable) environment.clone();
213 }
214 init(environment);
215 }
216
217 /**
218 * Initializes the initial context using the supplied environment.
219 * Environment properties are discussed in the class description.
220 *
221 * <p> This method will modify <tt>environment</tt> and save
222 * a reference to it. The caller may no longer modify it.
223 *
224 * @param environment
225 * environment used to create the initial context.
226 * Null indicates an empty environment.
227 *
228 * @throws NamingException if a naming exception is encountered
229 *
230 * @see #InitialContext(boolean)
231 * @since 1.3
232 */
233 protected void init(Hashtable<?, ?> environment)
234 throws NamingException {
235 myProps = ResourceManager.getInitialEnvironment(environment);
236
237 if (myProps.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
238 // user has specified initial context factory; try to get it
239 getDefaultInitCtx();
240 }
241 }
242
243 /**
244 * A static method to retrieve the named object.
245 * This is a shortcut method equivalent to invoking:
246 * <p>
247 * <code>
248 * InitialContext ic = new InitialContext();
249 * Object obj = ic.lookup();
250 * </code>
251 * <p> If <tt>name</tt> is empty, returns a new instance of this context
252 * (which represents the same naming context as this context, but its
253 * environment may be modified independently and it may be accessed
254 * concurrently).
255 *
256 * @param name
257 * the name of the object to look up
258 * @return the object bound to <tt>name</tt>
259 * @throws NamingException if a naming exception is encountered
260 *
261 * @see #doLookup(String)
262 * @see #lookup(Name)
263 * @since 1.6
264 */
265 public static <T> T doLookup(Name name) 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 name
273 * the name of the object to look up
274 * @return the object bound to <tt>name</tt>
275 * @throws NamingException if a naming exception is encountered
276 * @since 1.6
277 */
278 public static <T> T doLookup(String name) throws NamingException {
279 return (T) (new InitialContext()).lookup(name);
280 }
281
282 private static String getURLScheme(String str) {
283 int colon_posn = str.indexOf(':');
284 int slash_posn = str.indexOf('/');
285
286 if (colon_posn > 0
287 && (slash_posn == -1 || colon_posn < slash_posn))
288 return str.substring(0, colon_posn);
289 return null;
290 }
291
292 /**
293 * Retrieves the initial context by calling
294 * <code>NamingManager.getInitialContext()</code>
295 * and cache it in defaultInitCtx.
296 * Set <code>gotDefault</code> so that we know we've tried this before.
297 * @return The non-null cached initial context.
298 * @exception NoInitialContextException If cannot find an initial context.
299 * @exception NamingException If a naming exception was encountered.
300 */
301 protected Context getDefaultInitCtx() throws NamingException {
302 if (!gotDefault) {
303 defaultInitCtx = NamingManager.getInitialContext(myProps);
304 gotDefault = true;
305 }
306 if (defaultInitCtx == null)
307 throw new NoInitialContextException();
308
309 return defaultInitCtx;
310 }
311
312 /**
313 * Retrieves a context for resolving the string name <code>name</code>.
314 * If <code>name</code> name is a URL string, then attempt
315 * to find a URL context for it. If none is found, or if
316 * <code>name</code> is not a URL string, then return
317 * <code>getDefaultInitCtx()</code>.
318 *<p>
319 * See getURLOrDefaultInitCtx(Name) for description
320 * of how a subclass should use this method.
321 * @param name The non-null name for which to get the context.
322 * @return A URL context for <code>name</code> or the cached
323 * initial context. The result cannot be null.
324 * @exception NoInitialContextException If cannot find an initial context.
325 * @exception NamingException In a naming exception is encountered.
326 * @see javax.naming.spi.NamingManager#getURLContext
327 */
328 protected Context getURLOrDefaultInitCtx(String name)
329 throws NamingException {
330 if (NamingManager.hasInitialContextFactoryBuilder()) {
331 return getDefaultInitCtx();
332 }
333 String scheme = getURLScheme(name);
334 if (scheme != null) {
335 Context ctx = NamingManager.getURLContext(scheme, myProps);
336 if (ctx != null) {
337 return ctx;
338 }
339 }
340 return getDefaultInitCtx();
341 }
342
343 /**
344 * Retrieves a context for resolving <code>name</code>.
345 * If the first component of <code>name</code> name is a URL string,
346 * then attempt to find a URL context for it. If none is found, or if
347 * the first component of <code>name</code> is not a URL string,
348 * then return <code>getDefaultInitCtx()</code>.
349 *<p>
350 * When creating a subclass of InitialContext, use this method as
351 * follows.
352 * Define a new method that uses this method to get an initial
353 * context of the desired subclass.
354 * <p><blockquote><pre>
355 * protected XXXContext getURLOrDefaultInitXXXCtx(Name name)
356 * throws NamingException {
357 * Context answer = getURLOrDefaultInitCtx(name);
358 * if (!(answer instanceof XXXContext)) {
359 * if (answer == null) {
360 * throw new NoInitialContextException();
361 * } else {
362 * throw new NotContextException("Not an XXXContext");
363 * }
364 * }
365 * return (XXXContext)answer;
366 * }
367 * </pre></blockquote>
368 * When providing implementations for the new methods in the subclass,
369 * use this newly defined method to get the initial context.
370 * <p><blockquote><pre>
371 * public Object XXXMethod1(Name name, ...) {
372 * throws NamingException {
373 * return getURLOrDefaultInitXXXCtx(name).XXXMethod1(name, ...);
374 * }
375 * </pre></blockquote>
376 *
377 * @param name The non-null name for which to get the context.
378 * @return A URL context for <code>name</code> or the cached
379 * initial context. The result cannot be null.
380 * @exception NoInitialContextException If cannot find an initial context.
381 * @exception NamingException In a naming exception is encountered.
382 *
383 * @see javax.naming.spi.NamingManager#getURLContext
384 */
385 protected Context getURLOrDefaultInitCtx(Name name)
386 throws NamingException {
387 if (NamingManager.hasInitialContextFactoryBuilder()) {
388 return getDefaultInitCtx();
389 }
390 if (name.size() > 0) {
391 String first = name.get(0);
392 String scheme = getURLScheme(first);
393 if (scheme != null) {
394 Context ctx = NamingManager.getURLContext(scheme,
395 myProps);
396 if (ctx != null) {
397 return ctx;
398 }
399 }
400 }
401 return getDefaultInitCtx();
402 }
403
404 // Context methods
405 // Most Javadoc is deferred to the Context interface.
406
407 public Object lookup(String name) throws NamingException {
408 return getURLOrDefaultInitCtx(name).lookup(name);
409 }
410
411 public Object lookup(Name name) throws NamingException {
412 return getURLOrDefaultInitCtx(name).lookup(name);
413 }
414
415 public void bind(String name, Object obj) throws NamingException {
416 getURLOrDefaultInitCtx(name).bind(name, obj);
417 }
418
419 public void bind(Name name, Object obj) throws NamingException {
420 getURLOrDefaultInitCtx(name).bind(name, obj);
421 }
422
423 public void rebind(String name, Object obj) throws NamingException {
424 getURLOrDefaultInitCtx(name).rebind(name, obj);
425 }
426
427 public void rebind(Name name, Object obj) throws NamingException {
428 getURLOrDefaultInitCtx(name).rebind(name, obj);
429 }
430
431 public void unbind(String name) throws NamingException {
432 getURLOrDefaultInitCtx(name).unbind(name);
433 }
434
435 public void unbind(Name name) throws NamingException {
436 getURLOrDefaultInitCtx(name).unbind(name);
437 }
438
439 public void rename(String oldName, String newName)
440 throws NamingException {
441 getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
442 }
443
444 public void rename(Name oldName, Name newName)
445 throws NamingException {
446 getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
447 }
448
449 public NamingEnumeration<NameClassPair> list(String name)
450 throws NamingException {
451 return (getURLOrDefaultInitCtx(name).list(name));
452 }
453
454 public NamingEnumeration<NameClassPair> list(Name name)
455 throws NamingException {
456 return (getURLOrDefaultInitCtx(name).list(name));
457 }
458
459 public NamingEnumeration<Binding> listBindings(String name)
460 throws NamingException {
461 return getURLOrDefaultInitCtx(name).listBindings(name);
462 }
463
464 public NamingEnumeration<Binding> listBindings(Name name)
465 throws NamingException {
466 return getURLOrDefaultInitCtx(name).listBindings(name);
467 }
468
469 public void destroySubcontext(String name) throws NamingException {
470 getURLOrDefaultInitCtx(name).destroySubcontext(name);
471 }
472
473 public void destroySubcontext(Name name) throws NamingException {
474 getURLOrDefaultInitCtx(name).destroySubcontext(name);
475 }
476
477 public Context createSubcontext(String name) throws NamingException {
478 return getURLOrDefaultInitCtx(name).createSubcontext(name);
479 }
480
481 public Context createSubcontext(Name name) throws NamingException {
482 return getURLOrDefaultInitCtx(name).createSubcontext(name);
483 }
484
485 public Object lookupLink(String name) throws NamingException {
486 return getURLOrDefaultInitCtx(name).lookupLink(name);
487 }
488
489 public Object lookupLink(Name name) throws NamingException {
490 return getURLOrDefaultInitCtx(name).lookupLink(name);
491 }
492
493 public NameParser getNameParser(String name) throws NamingException {
494 return getURLOrDefaultInitCtx(name).getNameParser(name);
495 }
496
497 public NameParser getNameParser(Name name) throws NamingException {
498 return getURLOrDefaultInitCtx(name).getNameParser(name);
499 }
500
501 /**
502 * Composes the name of this context with a name relative to
503 * this context.
504 * Since an initial context may never be named relative
505 * to any context other than itself, the value of the
506 * <tt>prefix</tt> parameter must be an empty name (<tt>""</tt>).
507 */
508 public String composeName(String name, String prefix)
509 throws NamingException {
510 return name;
511 }
512
513 /**
514 * Composes the name of this context with a name relative to
515 * this context.
516 * Since an initial context may never be named relative
517 * to any context other than itself, the value of the
518 * <tt>prefix</tt> parameter must be an empty name.
519 */
520 public Name composeName(Name name, Name prefix)
521 throws NamingException {
522 return (Name) name.clone();
523 }
524
525 public Object addToEnvironment(String propName, Object propVal)
526 throws NamingException {
527 myProps.put(propName, propVal);
528 return getDefaultInitCtx().addToEnvironment(propName, propVal);
529 }
530
531 public Object removeFromEnvironment(String propName)
532 throws NamingException {
533 myProps.remove(propName);
534 return getDefaultInitCtx().removeFromEnvironment(propName);
535 }
536
537 public Hashtable<?, ?> getEnvironment() throws NamingException {
538 return getDefaultInitCtx().getEnvironment();
539 }
540
541 public void close() throws NamingException {
542 myProps = null;
543 if (defaultInitCtx != null) {
544 defaultInitCtx.close();
545 defaultInitCtx = null;
546 }
547 gotDefault = false;
548 }
549
550 public String getNameInNamespace() throws NamingException {
551 return getDefaultInitCtx().getNameInNamespace();
552 }
553 };
|