001 /* InitialContext.java -- Initial naming context.
002 Copyright (C) 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038
039 package javax.naming;
040
041 import java.applet.Applet;
042 import java.io.IOException;
043 import java.io.InputStream;
044 import java.net.URL;
045 import java.util.Enumeration;
046 import java.util.HashSet;
047 import java.util.Hashtable;
048 import java.util.Properties;
049
050 import javax.naming.spi.NamingManager;
051
052 /**
053 * The starting context for performing naming operations. All naming operations
054 * are performed in the scope of some context. The initial context is the
055 * starting point for the name resolution.
056 */
057 public class InitialContext implements Context
058 {
059 /**
060 * Contains the default initial context. This value is returned by
061 * {@link NamingManager#getInitialContext}. It is set by this method
062 * when calling it first time. The subsequent calls return the value of
063 * this field.
064 */
065 protected Context defaultInitCtx;
066
067 /**
068 * Indicates if the initial context was obtained by calling
069 * {@link NamingManager#getInitialContext}.
070 */
071 protected boolean gotDefault = false;
072
073 /**
074 * The environment, associated with this initial context.
075 */
076 protected Hashtable<Object,Object> myProps;
077
078 /**
079 * The list of the properties, to that the second alternative value must
080 * be appended after the colon to the first possible value. Used in
081 * {@link #merge(Hashtable, Hashtable)}
082 */
083 static final HashSet<String> colon_list;
084 static
085 {
086 colon_list = new HashSet<String>();
087 colon_list.add(Context.OBJECT_FACTORIES);
088 colon_list.add(Context.URL_PKG_PREFIXES);
089 colon_list.add(Context.STATE_FACTORIES);
090 }
091
092 /**
093 * The properties that are searched in the agreed places in the
094 * {@link #init(Hashtable)} method.
095 */
096 static final String[] use_properties =
097 {
098 Context.DNS_URL,
099 Context.INITIAL_CONTEXT_FACTORY,
100 Context.OBJECT_FACTORIES,
101 Context.PROVIDER_URL,
102 Context.STATE_FACTORIES,
103 Context.URL_PKG_PREFIXES,
104 };
105
106
107 /**
108 * Creates the new initial context with the given properties.
109 *
110 * @param environment the properties, used by the initial context being
111 * created.
112 * @throws NamingException
113 */
114 public InitialContext(Hashtable<?,?> environment) throws NamingException
115 {
116 init(environment);
117 }
118
119 /**
120 * Creates the initial context with the possibility to delay its
121 * initialisation.
122 *
123 * @param lazy specified if the initialization should not be performed by this
124 * constructor (true). If the valueis false, it works the same way as
125 * the parameterless constructor.
126 * @throws NamingException
127 */
128 protected InitialContext(boolean lazy) throws NamingException
129 {
130 if (! lazy)
131 init(null);
132 }
133
134 /**
135 * Creates teh new initial context with no properties. Same as
136 * InitialContext(null).
137 *
138 * @throws NamingException
139 */
140 public InitialContext() throws NamingException
141 {
142 init(null);
143 }
144
145 /**
146 * <p>
147 * Initialises the context, using the properties, specified in the passed
148 * table.
149 * </p>
150 * The missing properties are additionally obtained (in order) from the
151 * following locations:
152 * <ul>
153 * <li>If the passed parameter contains the key Context.APPLET, its value
154 * must be the instance of the {@link Applet}. Then the properties are
155 * requested via {@link Applet#getParameter(String)}.</li>
156 * <li>The value of the system property is used.</li>
157 * <li>The resource "jndi.properties" is requested from the context class
158 * loader of the current thread</li>
159 * <li>The property file "jndi.properties" is read from the location,
160 * specified by the system property "gnu.classpath.home.url".
161 * </ul>
162 * </p>
163 *
164 * @param environment the table of the properties, may be null. The method
165 * modifies the table and stores the reference to it. The caller must
166 * not later reuse this structure for other purposes.
167 * @since 1.3
168 */
169 protected void init(Hashtable<?, ?> environment) throws NamingException
170 {
171 // If is documented that the caller should not modify the environment.
172 if (environment != null)
173 myProps = (Hashtable<Object, Object>) environment;
174 else
175 myProps = new Hashtable<Object, Object>();
176
177 Applet napplet = (Applet) myProps.get(Context.APPLET);
178
179 Properties pApplet = null;
180 if (napplet != null)
181 pApplet = new Properties();
182 Properties pSystem = new Properties();
183 Object value;
184
185 for (int i = use_properties.length - 1; i >= 0; i--)
186 {
187 String key = use_properties[i];
188 if (napplet != null)
189 {
190 value = napplet.getParameter(key);
191 if (value != null)
192 pApplet.put(key, value);
193 }
194
195 value = System.getProperty(key);
196 if (value != null)
197 pSystem.put(key, value);
198 }
199
200 merge(myProps, pSystem);
201 if (pApplet != null)
202 merge(myProps, pApplet);
203
204 try
205 {
206 Enumeration ep = Thread.currentThread().
207 getContextClassLoader().getResources("jndi.properties");
208 while (ep.hasMoreElements())
209 {
210 URL url = (URL) ep.nextElement();
211 Properties p = new Properties();
212
213 try
214 {
215 InputStream is = url.openStream();
216 p.load(is);
217 is.close();
218 }
219 catch (IOException e)
220 {
221 // Ignore.
222 }
223
224 merge(myProps, p);
225 }
226 }
227 catch (IOException e)
228 {
229 // Ignore.
230 }
231
232 String home = System.getProperty("gnu.classpath.home.url");
233 if (home != null)
234 {
235 String url = home + "/jndi.properties";
236 Properties p = new Properties();
237
238 try
239 {
240 InputStream is = new URL(url).openStream();
241 p.load(is);
242 is.close();
243 }
244 catch (IOException e)
245 {
246 // Ignore.
247 }
248
249 merge(myProps, p);
250 }
251 }
252
253 /**
254 * Merge the content of the two tables. If the second table contains the key
255 * that is missing in the first table, this key - value pair is copied to the
256 * first table. If both first and second tables contain the same key AND the
257 * {@link #colon_list} set also contains this key, the value from the second
258 * table is appended to the value from the first table after semicolon, and
259 * the resulted value replaces the value in the first table.
260 *
261 * @param primary the first table to merge. The merged result is also stored
262 * in this table.
263 * @param additional the second table, from where additional values are taken
264 */
265 static void merge (Hashtable<Object, Object> primary,
266 Hashtable<Object, Object> additional)
267 {
268 Enumeration en = additional.keys();
269
270 while (en.hasMoreElements())
271 {
272 String key2 = (String) en.nextElement();
273 Object value1 = primary.get(key2);
274 if (value1 == null)
275 primary.put(key2, additional.get(key2));
276 else if (colon_list.contains(key2))
277 {
278 String value2 = (String) additional.get(key2);
279 primary.put(key2, (String) value1 + ":" + value2);
280 }
281 }
282 }
283
284 /**
285 * Get the default initial context. If {@link #gotDefault} == false, this
286 * method obtains the initial context from the naming manager and sets
287 * gotDefault to true. Otherwise the cached value ({@link #defaultInitCtx} is
288 * returned.
289 *
290 * @return the default initial context
291 * @throws NamingException
292 */
293 protected Context getDefaultInitCtx() throws NamingException
294 {
295 if (! gotDefault)
296 {
297 defaultInitCtx = NamingManager.getInitialContext(myProps);
298 gotDefault = true;
299 }
300 return defaultInitCtx;
301 }
302
303 /**
304 * Obtains the context for resolving the given name. If the first component of
305 * the name is the URL string, this method tries to find the corressponding
306 * URL naming context. If it is not an URL string, or the URL context is not
307 * found, the default initial context is returned.
308 *
309 * @param name the name, for that it is required to obtain the context.
310 * @return the context for resolving the name.
311 * @throws NamingException
312 */
313 protected Context getURLOrDefaultInitCtx(Name name) throws NamingException
314 {
315 if (name.size() > 0)
316 return getURLOrDefaultInitCtx(name.get(0));
317 else
318 return getDefaultInitCtx();
319 }
320
321 /**
322 * Obtains the context for resolving the given name. If the first component of
323 * the name is the URL string, this method tries to find the corressponding
324 * URL naming context. If it is not an URL string, or the URL context is not
325 * found, the default initial context is returned.
326 *
327 * @param name the name, for that it is required to obtain the context.
328 * @return the context for resolving the name.
329 * @throws NamingException
330 */
331 protected Context getURLOrDefaultInitCtx(String name) throws NamingException
332 {
333 String scheme = null;
334
335 if (NamingManager.hasInitialContextFactoryBuilder())
336 return getDefaultInitCtx();
337 int colon = name.indexOf(':');
338 int slash = name.indexOf('/');
339 if (colon > 0 && (slash == - 1 || colon < slash))
340 scheme = name.substring(0, colon);
341 if (scheme != null)
342 {
343 Context context = NamingManager.getURLContext(scheme, myProps);
344 if (context != null)
345 return context;
346 }
347
348 return getDefaultInitCtx();
349 }
350
351 /** @inheritDoc */
352 public void bind (Name name, Object obj) throws NamingException
353 {
354 getURLOrDefaultInitCtx (name).bind (name, obj);
355 }
356
357 /** @inheritDoc */
358 public void bind (String name, Object obj) throws NamingException
359 {
360 getURLOrDefaultInitCtx (name).bind (name, obj);
361 }
362
363 /** @inheritDoc */
364 public Object lookup (Name name) throws NamingException
365 {
366 try
367 {
368 return getURLOrDefaultInitCtx (name).lookup (name);
369 }
370 catch (CannotProceedException cpe)
371 {
372 Context ctx = NamingManager.getContinuationContext (cpe);
373 return ctx.lookup (cpe.getRemainingName());
374 }
375 }
376
377 /** @inheritDoc */
378 public Object lookup (String name) throws NamingException
379 {
380 try
381 {
382 return getURLOrDefaultInitCtx (name).lookup (name);
383 }
384 catch (CannotProceedException cpe)
385 {
386 Context ctx = NamingManager.getContinuationContext (cpe);
387 return ctx.lookup (cpe.getRemainingName());
388 }
389 }
390
391 /** @inheritDoc */
392 public void rebind (Name name, Object obj) throws NamingException
393 {
394 getURLOrDefaultInitCtx (name).rebind (name, obj);
395 }
396
397 /** @inheritDoc */
398 public void rebind (String name, Object obj) throws NamingException
399 {
400 getURLOrDefaultInitCtx (name).rebind (name, obj);
401 }
402
403 /** @inheritDoc */
404 public void unbind (Name name) throws NamingException
405 {
406 getURLOrDefaultInitCtx (name).unbind (name);
407 }
408
409 /** @inheritDoc */
410 public void unbind (String name) throws NamingException
411 {
412 getURLOrDefaultInitCtx (name).unbind (name);
413 }
414
415 /** @inheritDoc */
416 public void rename (Name oldName, Name newName) throws NamingException
417 {
418 getURLOrDefaultInitCtx (oldName).rename (oldName, newName);
419 }
420
421 /** @inheritDoc */
422 public void rename (String oldName, String newName) throws NamingException
423 {
424 getURLOrDefaultInitCtx (oldName).rename (oldName, newName);
425 }
426
427 /** @inheritDoc */
428 public NamingEnumeration<NameClassPair> list (Name name) throws NamingException
429 {
430 return getURLOrDefaultInitCtx (name).list (name);
431 }
432
433 /** @inheritDoc */
434 public NamingEnumeration<NameClassPair> list (String name) throws NamingException
435 {
436 return getURLOrDefaultInitCtx (name).list (name);
437 }
438
439 /** @inheritDoc */
440 public NamingEnumeration<Binding> listBindings (Name name) throws NamingException
441 {
442 return getURLOrDefaultInitCtx (name).listBindings (name);
443 }
444
445 /** @inheritDoc */
446 public NamingEnumeration<Binding> listBindings (String name) throws NamingException
447 {
448 return getURLOrDefaultInitCtx (name).listBindings (name);
449 }
450
451 /** @inheritDoc */
452 public void destroySubcontext (Name name) throws NamingException
453 {
454 getURLOrDefaultInitCtx (name).destroySubcontext (name);
455 }
456
457 /** @inheritDoc */
458 public void destroySubcontext (String name) throws NamingException
459 {
460 getURLOrDefaultInitCtx (name).destroySubcontext (name);
461 }
462
463 /** @inheritDoc */
464 public Context createSubcontext (Name name) throws NamingException
465 {
466 return getURLOrDefaultInitCtx (name).createSubcontext (name);
467 }
468
469 /** @inheritDoc */
470 public Context createSubcontext (String name) throws NamingException
471 {
472 return getURLOrDefaultInitCtx (name).createSubcontext (name);
473 }
474
475 /** @inheritDoc */
476 public Object lookupLink (Name name) throws NamingException
477 {
478 return getURLOrDefaultInitCtx (name).lookupLink (name);
479 }
480
481 /** @inheritDoc */
482 public Object lookupLink (String name) throws NamingException
483 {
484 return getURLOrDefaultInitCtx (name).lookupLink (name);
485 }
486
487 /** @inheritDoc */
488 public NameParser getNameParser (Name name) throws NamingException
489 {
490 return getURLOrDefaultInitCtx (name).getNameParser (name);
491 }
492
493 /** @inheritDoc */
494 public NameParser getNameParser (String name) throws NamingException
495 {
496 return getURLOrDefaultInitCtx (name).getNameParser (name);
497 }
498
499 /** @inheritDoc */
500 public Name composeName (Name name, Name prefix) throws NamingException
501 {
502 return getURLOrDefaultInitCtx (name).composeName (name, prefix);
503 }
504
505 /** @inheritDoc */
506 public String composeName (String name,
507 String prefix) throws NamingException
508 {
509 return getURLOrDefaultInitCtx (name).composeName (name, prefix);
510 }
511
512 /** @inheritDoc */
513 public Object addToEnvironment (String propName,
514 Object propVal) throws NamingException
515 {
516 return myProps.put (propName, propVal);
517 }
518
519 /** @inheritDoc */
520 public Object removeFromEnvironment (String propName) throws NamingException
521 {
522 return myProps.remove (propName);
523 }
524
525 /** @inheritDoc */
526 public Hashtable<?,?> getEnvironment () throws NamingException
527 {
528 return myProps;
529 }
530
531 /** @inheritDoc */
532 public void close () throws NamingException
533 {
534 myProps = null;
535 defaultInitCtx = null;
536 }
537
538 /**
539 * This operation is not supported for the initial naming context.
540 *
541 * @throws OperationNotSupportedException always, unless the method is
542 * overridden in the derived class.
543 */
544 public String getNameInNamespace () throws NamingException
545 {
546 throw new OperationNotSupportedException ();
547 }
548 }