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