001/* InitialContext.java -- Initial naming context. 002 Copyright (C) 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.naming; 040 041import java.applet.Applet; 042import java.io.IOException; 043import java.io.InputStream; 044import java.net.URL; 045import java.util.Enumeration; 046import java.util.HashSet; 047import java.util.Hashtable; 048import java.util.Properties; 049 050import 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 */ 057public 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}