1 /* InitialContext.java -- Initial naming context.
2    Copyright (C) 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.naming;
40 
41 import java.applet.Applet;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.net.URL;
45 import java.util.Enumeration;
46 import java.util.HashSet;
47 import java.util.Hashtable;
48 import java.util.Properties;
49 
50 import javax.naming.spi.NamingManager;
51 
52 /**
53  * The starting context for performing naming operations. All naming operations
54  * are performed in the scope of some context. The initial context is the
55  * starting point for the name resolution.
56  */
57 public class InitialContext implements Context
58 {
59   /**
60    * Contains the default initial context. This value is returned by
61    * {@link NamingManager#getInitialContext}. It is set by this method
62    * when calling it first time. The subsequent calls return the value of
63    * this field.
64    */
65   protected Context defaultInitCtx;
66 
67   /**
68    * Indicates if the initial context was obtained by calling
69    * {@link NamingManager#getInitialContext}.
70    */
71   protected boolean gotDefault = false;
72 
73   /**
74    * The environment, associated with this initial context.
75    */
76   protected Hashtable<Object,Object> myProps;
77 
78   /**
79    * The list of the properties, to that the second alternative value must
80    * be appended after the colon to the first possible value. Used in
81    * {@link #merge(Hashtable, Hashtable)}
82    */
83   static final HashSet<String> colon_list;
84   static
85     {
86       colon_list = new HashSet<String>();
87       colon_list.add(Context.OBJECT_FACTORIES);
88       colon_list.add(Context.URL_PKG_PREFIXES);
89       colon_list.add(Context.STATE_FACTORIES);
90     }
91 
92    /**
93     * The properties that are searched in the agreed places in the
94     * {@link #init(Hashtable)} method.
95     */
96     static final String[] use_properties =
97       {
98         Context.DNS_URL,
99         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    */
InitialContext(Hashtable<?,?> environment)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    */
InitialContext(boolean lazy)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    */
InitialContext()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    */
init(Hashtable<?, ?> environment)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    */
merge(Hashtable<Object, Object> primary, Hashtable<Object, Object> additional)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    */
getDefaultInitCtx()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    */
getURLOrDefaultInitCtx(Name name)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    */
getURLOrDefaultInitCtx(String name)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 */
bind(Name name, Object obj)352   public void bind (Name name, Object obj) throws NamingException
353   {
354     getURLOrDefaultInitCtx (name).bind (name, obj);
355   }
356 
357   /** @inheritDoc */
bind(String name, Object obj)358   public void bind (String name, Object obj) throws NamingException
359   {
360     getURLOrDefaultInitCtx (name).bind (name, obj);
361   }
362 
363   /** @inheritDoc */
lookup(Name name)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 */
lookup(String name)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 */
rebind(Name name, Object obj)392   public void rebind (Name name, Object obj) throws NamingException
393   {
394     getURLOrDefaultInitCtx (name).rebind (name, obj);
395   }
396 
397   /** @inheritDoc */
rebind(String name, Object obj)398   public void rebind (String name, Object obj) throws NamingException
399   {
400     getURLOrDefaultInitCtx (name).rebind (name, obj);
401   }
402 
403   /** @inheritDoc */
unbind(Name name)404   public void unbind (Name name) throws NamingException
405   {
406     getURLOrDefaultInitCtx (name).unbind (name);
407   }
408 
409   /** @inheritDoc */
unbind(String name)410   public void unbind (String name) throws NamingException
411   {
412     getURLOrDefaultInitCtx (name).unbind (name);
413   }
414 
415   /** @inheritDoc */
rename(Name oldName, Name newName)416   public void rename (Name oldName, Name newName) throws NamingException
417   {
418     getURLOrDefaultInitCtx (oldName).rename (oldName, newName);
419   }
420 
421   /** @inheritDoc */
rename(String oldName, String newName)422   public void rename (String oldName, String newName) throws NamingException
423   {
424     getURLOrDefaultInitCtx (oldName).rename (oldName, newName);
425   }
426 
427   /** @inheritDoc */
list(Name name)428   public NamingEnumeration<NameClassPair> list (Name name) throws NamingException
429   {
430     return getURLOrDefaultInitCtx (name).list (name);
431   }
432 
433   /** @inheritDoc */
list(String name)434   public NamingEnumeration<NameClassPair> list (String name) throws NamingException
435   {
436     return getURLOrDefaultInitCtx (name).list (name);
437   }
438 
439   /** @inheritDoc */
listBindings(Name name)440   public NamingEnumeration<Binding> listBindings (Name name) throws NamingException
441   {
442     return getURLOrDefaultInitCtx (name).listBindings (name);
443   }
444 
445   /** @inheritDoc */
listBindings(String name)446   public NamingEnumeration<Binding> listBindings (String name) throws NamingException
447   {
448     return getURLOrDefaultInitCtx (name).listBindings (name);
449   }
450 
451   /** @inheritDoc */
destroySubcontext(Name name)452   public void destroySubcontext (Name name) throws NamingException
453   {
454     getURLOrDefaultInitCtx (name).destroySubcontext (name);
455   }
456 
457   /** @inheritDoc */
destroySubcontext(String name)458   public void destroySubcontext (String name) throws NamingException
459   {
460     getURLOrDefaultInitCtx (name).destroySubcontext (name);
461   }
462 
463   /** @inheritDoc */
createSubcontext(Name name)464   public Context createSubcontext (Name name) throws NamingException
465   {
466     return getURLOrDefaultInitCtx (name).createSubcontext (name);
467   }
468 
469   /** @inheritDoc */
createSubcontext(String name)470   public Context createSubcontext (String name) throws NamingException
471   {
472     return getURLOrDefaultInitCtx (name).createSubcontext (name);
473   }
474 
475   /** @inheritDoc */
lookupLink(Name name)476   public Object lookupLink (Name name) throws NamingException
477   {
478     return getURLOrDefaultInitCtx (name).lookupLink (name);
479   }
480 
481   /** @inheritDoc */
lookupLink(String name)482   public Object lookupLink (String name) throws NamingException
483   {
484     return getURLOrDefaultInitCtx (name).lookupLink (name);
485   }
486 
487   /** @inheritDoc */
getNameParser(Name name)488   public NameParser getNameParser (Name name) throws NamingException
489   {
490     return getURLOrDefaultInitCtx (name).getNameParser (name);
491   }
492 
493   /** @inheritDoc */
getNameParser(String name)494   public NameParser getNameParser (String name) throws NamingException
495   {
496     return getURLOrDefaultInitCtx (name).getNameParser (name);
497   }
498 
499   /** @inheritDoc */
composeName(Name name, Name prefix)500   public Name composeName (Name name, Name prefix) throws NamingException
501   {
502     return getURLOrDefaultInitCtx (name).composeName (name, prefix);
503   }
504 
505   /** @inheritDoc */
composeName(String name, String prefix)506   public String composeName (String name,
507                              String prefix) throws NamingException
508   {
509     return getURLOrDefaultInitCtx (name).composeName (name, prefix);
510   }
511 
512   /** @inheritDoc */
addToEnvironment(String propName, Object propVal)513   public Object addToEnvironment (String propName,
514                                   Object propVal) throws NamingException
515   {
516     return myProps.put (propName, propVal);
517   }
518 
519   /** @inheritDoc */
removeFromEnvironment(String propName)520   public Object removeFromEnvironment (String propName) throws NamingException
521   {
522     return myProps.remove (propName);
523   }
524 
525   /** @inheritDoc */
getEnvironment()526   public Hashtable<?,?> getEnvironment () throws NamingException
527   {
528     return myProps;
529   }
530 
531   /** @inheritDoc */
close()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    */
getNameInNamespace()544   public String getNameInNamespace () throws NamingException
545   {
546     throw new OperationNotSupportedException ();
547   }
548 }
549