1. /*
  2. * @(#)InitialContext.java 1.8 00/02/02
  3. *
  4. * Copyright 1999, 2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.naming;
  11. import java.util.Hashtable;
  12. import javax.naming.spi.NamingManager;
  13. import com.sun.naming.internal.ResourceManager;
  14. /**
  15. * This class is the starting context for performing naming operations.
  16. *<p>
  17. * All naming operations are relative to a context.
  18. * The initial context implements the Context interface and
  19. * provides the starting point for resolution of names.
  20. *<p>
  21. * <a name=ENVIRONMENT></a>
  22. * When the initial context is constructed, its environment
  23. * is initialized with properties defined in the environment parameter
  24. * passed to the constructor, and in any
  25. * <a href=Context.html#RESOURCEFILES>application resource files</a>.
  26. * In addition, a small number of standard JNDI properties may
  27. * be specified as system properties or as applet parameters
  28. * (through the use of {@link Context#APPLET}).
  29. * These special properties are listed in the field detail sections of the
  30. * <a href=Context.html#field_detail><tt>Context</tt></a> and
  31. * <a href=ldap/LdapContext.html#field_detail><tt>LdapContext</tt></a>
  32. * interface documentation.
  33. *<p>
  34. * JNDI determines each property's value by merging
  35. * the values from the following two sources, in order:
  36. * <ol>
  37. * <li>
  38. * The first occurrence of the property from the constructor's
  39. * environment parameter and (for appropriate properties) the applet
  40. * parameters and system properties.
  41. * <li>
  42. * The application resource files (<tt>jndi.properties</tt>).
  43. * </ol>
  44. * For each property found in both of these two sources, or in
  45. * more than one application resource file, the property's value
  46. * is determined as follows. If the property is
  47. * one of the standard JNDI properties that specify a list of JNDI
  48. * factories (see <a href=Context.html#LISTPROPS><tt>Context</tt></a>),
  49. * all of the values are
  50. * concatenated into a single colon-separated list. For other
  51. * properties, only the first value found is used.
  52. *
  53. *<p>
  54. * The initial context implementation is determined at runtime.
  55. * The default policy uses the environment property
  56. * "{@link Context#INITIAL_CONTEXT_FACTORY java.naming.factory.initial}",
  57. * which contains the class name of the initial context factory.
  58. * An exception to this policy is made when resolving URL strings, as described
  59. * below.
  60. *<p>
  61. * When a URL string (a <tt>String</tt> of the form
  62. * <em>scheme_id:rest_of_name</em>) is passed as a name parameter to
  63. * any method, a URL context factory for handling that scheme is
  64. * located and used to resolve the URL. If no such factory is found,
  65. * the initial context specified by
  66. * <tt>"java.naming.factory.initial"</tt> is used. Similarly, when a
  67. * <tt>CompositeName</tt> object whose first component is a URL string is
  68. * passed as a name parameter to any method, a URL context factory is
  69. * located and used to resolve the first name component.
  70. * See {@link NamingManager#getURLContext
  71. * <tt>NamingManager.getURLContext()</tt>} for a description of how URL
  72. * context factories are located.
  73. *<p>
  74. * This default policy of locating the initial context and URL context
  75. * factories may be overridden
  76. * by calling
  77. * <tt>NamingManager.setInitialContextFactoryBuilder()</tt>.
  78. *<p>
  79. * NoInitialContextException is thrown when an initial context cannot
  80. * be instantiated. This exception can be thrown during any interaction
  81. * with the InitialContext, not only when the InitialContext is constructed.
  82. * For example, the implementation of the initial context might lazily
  83. * retrieve the context only when actual methods are invoked on it.
  84. * The application should not have any dependency on when the existence
  85. * of an initial context is determined.
  86. *<p>
  87. * When the environment property "java.naming.factory.initial" is
  88. * non-null, the InitialContext constructor will attempt to create the
  89. * initial context specified therein. At that time, the initial context factory
  90. * involved might throw an exception if a problem is encountered. However,
  91. * it is provider implementation-dependent when it verifies and indicates
  92. * to the users of the initial context any environment property- or
  93. * connection- related problems. It can do so lazily--delaying until
  94. * an operation is performed on the context, or eagerly, at the time
  95. * the context is constructed.
  96. *<p>
  97. * An InitialContext instance is not synchronized against concurrent
  98. * access by multiple threads. Multiple threads each manipulating a
  99. * different InitialContext instance need not synchronize.
  100. * Threads that need to access a single InitialContext instance
  101. * concurrently should synchronize amongst themselves and provide the
  102. * necessary locking.
  103. *
  104. * @author Rosanna Lee
  105. * @author Scott Seligman
  106. * @version 1.8 00/02/02
  107. *
  108. * @see Context
  109. * @see NamingManager#setInitialContextFactoryBuilder
  110. * NamingManager.setInitialContextFactoryBuilder
  111. * @since JNDI 1.1 / Java 2 Platform, Standard Edition, v 1.3
  112. */
  113. public class InitialContext implements Context {
  114. /**
  115. * The environment associated with this InitialContext.
  116. * It is initialized to null and is updated by the constructor
  117. * that accepts an environment or by the <tt>init()</tt> method.
  118. * @see #addToEnvironment
  119. * @see #removeFromEnvironment
  120. * @see #getEnvironment
  121. */
  122. protected Hashtable myProps = null;
  123. /**
  124. * Field holding the result of calling NamingManager.getInitialContext().
  125. * It is set by getDefaultInitCtx() the first time getDefaultInitCtx()
  126. * is called. Subsequent invocations of getDefaultInitCtx() return
  127. * the value of defaultInitCtx.
  128. * @see #getDefaultInitCtx
  129. */
  130. protected Context defaultInitCtx = null;
  131. /**
  132. * Field indicating whether the initial context has been obtained
  133. * by calling NamingManager.getInitialContext().
  134. * If true, its result is in <code>defaultInitCtx</code>.
  135. */
  136. protected boolean gotDefault = false;
  137. /**
  138. * Constructs an initial context with the option of not
  139. * initializing it. This may be used by a constructor in
  140. * a subclass when the value of the environment parameter
  141. * is not yet known at the time the <tt>InitialContext</tt>
  142. * constructor is called. The subclass's constructor will
  143. * call this constructor, compute the value of the environment,
  144. * and then call <tt>init()</tt> before returning.
  145. *
  146. * @param lazy
  147. * true means do not initialize the initial context; false
  148. * is equivalent to calling <tt>new InitialContext()</tt>
  149. * @throws NamingException if a naming exception is encountered
  150. *
  151. * @see #init(Hashtable)
  152. * @since 1.3
  153. */
  154. protected InitialContext(boolean lazy) throws NamingException {
  155. if (!lazy) {
  156. init(null);
  157. }
  158. }
  159. /**
  160. * Constructs an initial context.
  161. * No environment properties are supplied.
  162. * Equivalent to <tt>new InitialContext(null)</tt>.
  163. *
  164. * @throws NamingException if a naming exception is encountered
  165. *
  166. * @see #InitialContext(Hashtable)
  167. */
  168. public InitialContext() throws NamingException {
  169. init(null);
  170. }
  171. /**
  172. * Constructs an initial context using the supplied environment.
  173. * Environment properties are discussed in the class description.
  174. *
  175. * <p> This constructor will not modify <tt>environment</tt>
  176. * or save a reference to it, but may save a clone.
  177. *
  178. * @param environment
  179. * environment used to create the initial context.
  180. * Null indicates an empty environment.
  181. *
  182. * @throws NamingException if a naming exception is encountered
  183. */
  184. public InitialContext(Hashtable environment) throws NamingException {
  185. if (environment != null) {
  186. environment = (Hashtable)environment.clone();
  187. }
  188. init(environment);
  189. }
  190. /**
  191. * Initializes the initial context using the supplied environment.
  192. * Environment properties are discussed in the class description.
  193. *
  194. * <p> This method will modify <tt>environment</tt> and save
  195. * a reference to it. The caller may no longer modify it.
  196. *
  197. * @param environment
  198. * environment used to create the initial context.
  199. * Null indicates an empty environment.
  200. *
  201. * @throws NamingException if a naming exception is encountered
  202. *
  203. * @see #InitialContext(boolean)
  204. * @since 1.3
  205. */
  206. protected void init(Hashtable environment) throws NamingException {
  207. myProps = ResourceManager.getInitialEnvironment(environment);
  208. if (myProps.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
  209. // user has specified initial context factory; try to get it
  210. getDefaultInitCtx();
  211. }
  212. }
  213. private static String getURLScheme(String str) {
  214. int colon_posn = str.indexOf(':');
  215. int slash_posn = str.indexOf('/');
  216. if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
  217. return str.substring(0, colon_posn);
  218. return null;
  219. }
  220. /**
  221. * Retrieves the initial context by calling
  222. * <code>NamingManager.getInitialContext()</code>
  223. * and cache it in defaultInitCtx.
  224. * Set <code>gotDefault</code> so that we know we've tried this before.
  225. * @return The non-null cached initial context.
  226. * @exception NoInitialContextException If cannot find an initial context.
  227. * @exception NamingException If a naming exception was encountered.
  228. */
  229. protected Context getDefaultInitCtx() throws NamingException{
  230. if (!gotDefault) {
  231. defaultInitCtx = NamingManager.getInitialContext(myProps);
  232. gotDefault = true;
  233. }
  234. if (defaultInitCtx == null)
  235. throw new NoInitialContextException();
  236. return defaultInitCtx;
  237. }
  238. /**
  239. * Retrieves a context for resolving the string name <code>name</code>.
  240. * If <code>name</code> name is a URL string, then attempt
  241. * to find a URL context for it. If none is found, or if
  242. * <code>name</code> is not a URL string, then return
  243. * <code>getDefaultInitCtx()</code>.
  244. *<p>
  245. * See getURLOrDefaultInitCtx(Name) for description
  246. * of how a subclass should use this method.
  247. * @param name The non-null name for which to get the context.
  248. * @return A URL context for <code>name</code> or the cached
  249. * initial context. The result cannot be null.
  250. * @exception NoInitialContextException If cannot find an initial context.
  251. * @exception NamingException In a naming exception is encountered.
  252. * @see javax.naming.spi.NamingManager#getURLContext
  253. */
  254. protected Context getURLOrDefaultInitCtx(String name)
  255. throws NamingException {
  256. if (NamingManager.hasInitialContextFactoryBuilder()) {
  257. return getDefaultInitCtx();
  258. }
  259. String scheme = getURLScheme(name);
  260. if (scheme != null) {
  261. Context ctx = NamingManager.getURLContext(scheme, myProps);
  262. if (ctx != null) {
  263. return ctx;
  264. }
  265. }
  266. return getDefaultInitCtx();
  267. }
  268. /**
  269. * Retrieves a context for resolving <code>name</code>.
  270. * If the first component of <code>name</code> name is a URL string,
  271. * then attempt to find a URL context for it. If none is found, or if
  272. * the first component of <code>name</code> is not a URL string,
  273. * then return <code>getDefaultInitCtx()</code>.
  274. *<p>
  275. * When creating a subclass of InitialContext, use this method as
  276. * follows.
  277. * Define a new method that uses this method to get an initial
  278. * context of the desired subclass.
  279. * <p><blockquote><pre>
  280. * protected XXXContext getURLOrDefaultInitXXXCtx(Name name)
  281. * throws NamingException {
  282. * Context answer = getURLOrDefaultInitCtx(name);
  283. * if (!(answer instanceof XXXContext)) {
  284. * if (answer == null) {
  285. * throw new NoInitialContextException();
  286. * } else {
  287. * throw new NotContextException("Not an XXXContext");
  288. * }
  289. * }
  290. * return (XXXContext)answer;
  291. * }
  292. * </pre></blockquote>
  293. * When providing implementations for the new methods in the subclass,
  294. * use this newly defined method to get the initial context.
  295. * <p><blockquote><pre>
  296. * public Object XXXMethod1(Name name, ...) {
  297. * throws NamingException {
  298. * return getURLOrDefaultInitXXXCtx(name).XXXMethod1(name, ...);
  299. * }
  300. * </pre></blockquote>
  301. *
  302. * @param name The non-null name for which to get the context.
  303. * @return A URL context for <code>name</code> or the cached
  304. * initial context. The result cannot be null.
  305. * @exception NoInitialContextException If cannot find an initial context.
  306. * @exception NamingException In a naming exception is encountered.
  307. *
  308. * @see javax.naming.spi.NamingManager#getURLContext
  309. */
  310. protected Context getURLOrDefaultInitCtx(Name name)
  311. throws NamingException {
  312. if (NamingManager.hasInitialContextFactoryBuilder()) {
  313. return getDefaultInitCtx();
  314. }
  315. if (name.size() > 0) {
  316. String first = name.get(0);
  317. String scheme = getURLScheme(first);
  318. if (scheme != null) {
  319. Context ctx = NamingManager.getURLContext(scheme, myProps);
  320. if (ctx != null) {
  321. return ctx;
  322. }
  323. }
  324. }
  325. return getDefaultInitCtx();
  326. }
  327. // Context methods
  328. // Most Javadoc is deferred to the Context interface.
  329. public Object lookup(String name) throws NamingException {
  330. return getURLOrDefaultInitCtx(name).lookup(name);
  331. }
  332. public Object lookup(Name name) throws NamingException {
  333. return getURLOrDefaultInitCtx(name).lookup(name);
  334. }
  335. public void bind(String name, Object obj) throws NamingException {
  336. getURLOrDefaultInitCtx(name).bind(name, obj);
  337. }
  338. public void bind(Name name, Object obj) throws NamingException {
  339. getURLOrDefaultInitCtx(name).bind(name, obj);
  340. }
  341. public void rebind(String name, Object obj) throws NamingException {
  342. getURLOrDefaultInitCtx(name).rebind(name, obj);
  343. }
  344. public void rebind(Name name, Object obj) throws NamingException {
  345. getURLOrDefaultInitCtx(name).rebind(name, obj);
  346. }
  347. public void unbind(String name) throws NamingException {
  348. getURLOrDefaultInitCtx(name).unbind(name);
  349. }
  350. public void unbind(Name name) throws NamingException {
  351. getURLOrDefaultInitCtx(name).unbind(name);
  352. }
  353. public void rename(String oldName, String newName) throws NamingException {
  354. getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
  355. }
  356. public void rename(Name oldName, Name newName) throws NamingException {
  357. getURLOrDefaultInitCtx(oldName).rename(oldName, newName);
  358. }
  359. public NamingEnumeration list(String name) throws NamingException {
  360. return (getURLOrDefaultInitCtx(name).list(name));
  361. }
  362. public NamingEnumeration list(Name name) throws NamingException {
  363. return (getURLOrDefaultInitCtx(name).list(name));
  364. }
  365. public NamingEnumeration listBindings(String name)
  366. throws NamingException {
  367. return getURLOrDefaultInitCtx(name).listBindings(name);
  368. }
  369. public NamingEnumeration listBindings(Name name)
  370. throws NamingException {
  371. return getURLOrDefaultInitCtx(name).listBindings(name);
  372. }
  373. public void destroySubcontext(String name) throws NamingException {
  374. getURLOrDefaultInitCtx(name).destroySubcontext(name);
  375. }
  376. public void destroySubcontext(Name name) throws NamingException {
  377. getURLOrDefaultInitCtx(name).destroySubcontext(name);
  378. }
  379. public Context createSubcontext(String name) throws NamingException {
  380. return getURLOrDefaultInitCtx(name).createSubcontext(name);
  381. }
  382. public Context createSubcontext(Name name) throws NamingException {
  383. return getURLOrDefaultInitCtx(name).createSubcontext(name);
  384. }
  385. public Object lookupLink(String name) throws NamingException {
  386. return getURLOrDefaultInitCtx(name).lookupLink(name);
  387. }
  388. public Object lookupLink(Name name) throws NamingException {
  389. return getURLOrDefaultInitCtx(name).lookupLink(name);
  390. }
  391. public NameParser getNameParser(String name) throws NamingException {
  392. return getURLOrDefaultInitCtx(name).getNameParser(name);
  393. }
  394. public NameParser getNameParser(Name name) throws NamingException {
  395. return getURLOrDefaultInitCtx(name).getNameParser(name);
  396. }
  397. /**
  398. * Composes the name of this context with a name relative to
  399. * this context.
  400. * Since an initial context may never be named relative
  401. * to any context other than itself, the value of the
  402. * <tt>prefix</tt> parameter must be an empty name (<tt>""</tt>).
  403. */
  404. public String composeName(String name, String prefix)
  405. throws NamingException {
  406. return name;
  407. }
  408. /**
  409. * Composes the name of this context with a name relative to
  410. * this context.
  411. * Since an initial context may never be named relative
  412. * to any context other than itself, the value of the
  413. * <tt>prefix</tt> parameter must be an empty name.
  414. */
  415. public Name composeName(Name name, Name prefix) throws NamingException {
  416. return (Name)name.clone();
  417. }
  418. public Object addToEnvironment(String propName, Object propVal)
  419. throws NamingException {
  420. myProps.put(propName, propVal);
  421. return getDefaultInitCtx().addToEnvironment(propName, propVal);
  422. }
  423. public Object removeFromEnvironment(String propName)
  424. throws NamingException {
  425. myProps.remove(propName);
  426. return getDefaultInitCtx().removeFromEnvironment(propName);
  427. }
  428. public Hashtable getEnvironment() throws NamingException {
  429. return getDefaultInitCtx().getEnvironment();
  430. }
  431. public void close() throws NamingException {
  432. myProps = null;
  433. if (defaultInitCtx != null) {
  434. defaultInitCtx.close();
  435. defaultInitCtx = null;
  436. }
  437. gotDefault = false;
  438. }
  439. public String getNameInNamespace() throws NamingException {
  440. return getDefaultInitCtx().getNameInNamespace();
  441. }
  442. };