1. /*
  2. * @(#)DirectoryManager.java 1.10 03/05/09
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.naming.spi;
  8. import java.util.Hashtable;
  9. import javax.naming.Context;
  10. import javax.naming.Name;
  11. import javax.naming.Reference;
  12. import javax.naming.Referenceable;
  13. import javax.naming.NamingException;
  14. import javax.naming.CannotProceedException;
  15. import javax.naming.directory.DirContext;
  16. import javax.naming.directory.Attributes;
  17. import com.sun.naming.internal.ResourceManager;
  18. import com.sun.naming.internal.FactoryEnumeration;
  19. /**
  20. * This class contains methods for supporting <tt>DirContext</tt>
  21. * implementations.
  22. *<p>
  23. * This class is an extension of <tt>NamingManager</tt>. It contains methods
  24. * for use by service providers for accessing object factories and
  25. * state factories, and for getting continuation contexts for
  26. * supporting federation.
  27. *<p>
  28. * <tt>DirectoryManager</tt> is safe for concurrent access by multiple threads.
  29. *<p>
  30. * Except as otherwise noted,
  31. * a <tt>Name</tt>, <tt>Attributes</tt>, or environment parameter
  32. * passed to any method is owned by the caller.
  33. * The implementation will not modify the object or keep a reference
  34. * to it, although it may keep a reference to a clone or copy.
  35. *
  36. * @author Rosanna Lee
  37. * @author Scott Seligman
  38. * @version 1.10 03/05/09
  39. *
  40. * @see DirObjectFactory
  41. * @see DirStateFactory
  42. * @since 1.3
  43. */
  44. public class DirectoryManager extends NamingManager {
  45. /*
  46. * Disallow anyone from creating one of these.
  47. */
  48. DirectoryManager() {}
  49. /**
  50. * Creates a context in which to continue a <tt>DirContext</tt> operation.
  51. * Operates just like <tt>NamingManager.getContinuationContext()</tt>,
  52. * only the continuation context returned is a <tt>DirContext</tt>.
  53. *
  54. * @param cpe
  55. * The non-null exception that triggered this continuation.
  56. * @return A non-null <tt>DirContext</tt> object for continuing the operation.
  57. * @exception NamingException If a naming exception occurred.
  58. *
  59. * @see NamingManager#getContinuationContext(CannotProceedException)
  60. */
  61. public static DirContext getContinuationDirContext(
  62. CannotProceedException cpe) throws NamingException {
  63. Hashtable env = cpe.getEnvironment();
  64. if (env == null) {
  65. env = new Hashtable(7);
  66. } else {
  67. // Make a (shallow) copy of the environment.
  68. env = (Hashtable) env.clone();
  69. }
  70. env.put(CPE, cpe);
  71. return (new ContinuationDirContext(cpe, env));
  72. }
  73. /**
  74. * Creates an instance of an object for the specified object,
  75. * attributes, and environment.
  76. * <p>
  77. * This method is the same as <tt>NamingManager.getObjectInstance</tt>
  78. * except for the following differences:
  79. *<ul>
  80. *<li>
  81. * It accepts an <tt>Attributes</tt> parameter that contains attributes
  82. * associated with the object. The <tt>DirObjectFactory</tt> might use these
  83. * attributes to save having to look them up from the directory.
  84. *<li>
  85. * The object factories tried must implement either
  86. * <tt>ObjectFactory</tt> or <tt>DirObjectFactory</tt>.
  87. * If it implements <tt>DirObjectFactory</tt>,
  88. * <tt>DirObjectFactory.getObjectInstance()</tt> is used, otherwise,
  89. * <tt>ObjectFactory.getObjectInstance()</tt> is used.
  90. *</ul>
  91. * Service providers that implement the <tt>DirContext</tt> interface
  92. * should use this method, not <tt>NamingManager.getObjectInstance()</tt>.
  93. *<p>
  94. *
  95. * @param refInfo The possibly null object for which to create an object.
  96. * @param name The name of this object relative to <code>nameCtx</code>.
  97. * Specifying a name is optional; if it is
  98. * omitted, <code>name</code> should be null.
  99. * @param nameCtx The context relative to which the <code>name</code>
  100. * parameter is specified. If null, <code>name</code> is
  101. * relative to the default initial context.
  102. * @param environment The possibly null environment to
  103. * be used in the creation of the object factory and the object.
  104. * @param attrs The possibly null attributes associated with refInfo.
  105. * This might not be the complete set of attributes for refInfo;
  106. * you might be able to read more attributes from the directory.
  107. * @return An object created using <code>refInfo</code> and <tt>attrs</tt> or
  108. * <code>refInfo</code> if an object cannot be created by
  109. * a factory.
  110. * @exception NamingException If a naming exception was encountered
  111. * while attempting to get a URL context, or if one of the
  112. * factories accessed throws a NamingException.
  113. * @exception Exception If one of the factories accessed throws an
  114. * exception, or if an error was encountered while loading
  115. * and instantiating the factory and object classes.
  116. * A factory should only throw an exception if it does not want
  117. * other factories to be used in an attempt to create an object.
  118. * See <tt>DirObjectFactory.getObjectInstance()</tt>.
  119. * @see NamingManager#getURLContext
  120. * @see DirObjectFactory
  121. * @see DirObjectFactory#getObjectInstance
  122. * @since 1.3
  123. */
  124. public static Object getObjectInstance(Object refInfo,
  125. Name name, Context nameCtx, Hashtable environment, Attributes attrs)
  126. throws Exception {
  127. ObjectFactory factory;
  128. ObjectFactoryBuilder builder = getObjectFactoryBuilder();
  129. if (builder != null) {
  130. // builder must return non-null factory
  131. factory = builder.createObjectFactory(refInfo, environment);
  132. if (factory instanceof DirObjectFactory) {
  133. return ((DirObjectFactory)factory).getObjectInstance(
  134. refInfo, name, nameCtx, environment, attrs);
  135. } else {
  136. return factory.getObjectInstance(refInfo, name, nameCtx,
  137. environment);
  138. }
  139. }
  140. // use reference if possible
  141. Reference ref = null;
  142. if (refInfo instanceof Reference) {
  143. ref = (Reference) refInfo;
  144. } else if (refInfo instanceof Referenceable) {
  145. ref = ((Referenceable)(refInfo)).getReference();
  146. }
  147. Object answer;
  148. if (ref != null) {
  149. String f = ref.getFactoryClassName();
  150. if (f != null) {
  151. // if reference identifies a factory, use exclusively
  152. factory = getObjectFactoryFromReference(ref, f);
  153. if (factory instanceof DirObjectFactory) {
  154. return ((DirObjectFactory)factory).getObjectInstance(
  155. ref, name, nameCtx, environment, attrs);
  156. } else if (factory != null) {
  157. return factory.getObjectInstance(ref, name, nameCtx,
  158. environment);
  159. }
  160. // No factory found, so return original refInfo.
  161. // Will reach this point if factory class is not in
  162. // class path and reference does not contain a URL for it
  163. return refInfo;
  164. } else {
  165. // if reference has no factory, check for addresses
  166. // containing URLs
  167. // ignore name & attrs params; not used in URL factory
  168. answer = processURLAddrs(ref, name, nameCtx, environment);
  169. if (answer != null) {
  170. return answer;
  171. }
  172. }
  173. }
  174. // try using any specified factories
  175. answer = createObjectFromFactories(refInfo, name, nameCtx,
  176. environment, attrs);
  177. return (answer != null) ? answer : refInfo;
  178. }
  179. private static Object createObjectFromFactories(Object obj, Name name,
  180. Context nameCtx, Hashtable environment, Attributes attrs)
  181. throws Exception {
  182. FactoryEnumeration factories = ResourceManager.getFactories(
  183. Context.OBJECT_FACTORIES, environment, nameCtx);
  184. if (factories == null)
  185. return null;
  186. ObjectFactory factory;
  187. Object answer = null;
  188. // Try each factory until one succeeds
  189. while (answer == null && factories.hasMore()) {
  190. factory = (ObjectFactory)factories.next();
  191. if (factory instanceof DirObjectFactory) {
  192. answer = ((DirObjectFactory)factory).
  193. getObjectInstance(obj, name, nameCtx, environment, attrs);
  194. } else {
  195. answer =
  196. factory.getObjectInstance(obj, name, nameCtx, environment);
  197. }
  198. }
  199. return answer;
  200. }
  201. /**
  202. * Retrieves the state of an object for binding when given the original
  203. * object and its attributes.
  204. * <p>
  205. * This method is like <tt>NamingManager.getStateToBind</tt> except
  206. * for the following differences:
  207. *<ul>
  208. *<li>It accepts an <tt>Attributes</tt> parameter containing attributes
  209. * that were passed to the <tt>DirContext.bind()</tt> method.
  210. *<li>It returns a non-null <tt>DirStateFactory.Result</tt> instance
  211. * containing the object to be bound, and the attributes to
  212. * accompany the binding. Either the object or the attributes may be null.
  213. *<li>
  214. * The state factories tried must each implement either
  215. * <tt>StateFactory</tt> or <tt>DirStateFactory</tt>.
  216. * If it implements <tt>DirStateFactory</tt>, then
  217. * <tt>DirStateFactory.getStateToBind()</tt> is called; otherwise,
  218. * <tt>StateFactory.getStateToBind()</tt> is called.
  219. *</ul>
  220. *
  221. * Service providers that implement the <tt>DirContext</tt> interface
  222. * should use this method, not <tt>NamingManager.getStateToBind()</tt>.
  223. *<p>
  224. * See NamingManager.getStateToBind() for a description of how
  225. * the list of state factories to be tried is determined.
  226. *<p>
  227. * The object returned by this method is owned by the caller.
  228. * The implementation will not subsequently modify it.
  229. * It will contain either a new <tt>Attributes</tt> object that is
  230. * likewise owned by the caller, or a reference to the original
  231. * <tt>attrs</tt> parameter.
  232. *
  233. * @param obj The non-null object for which to get state to bind.
  234. * @param name The name of this object relative to <code>nameCtx</code>,
  235. * or null if no name is specified.
  236. * @param nameCtx The context relative to which the <code>name</code>
  237. * parameter is specified, or null if <code>name</code> is
  238. * relative to the default initial context.
  239. * @param environment The possibly null environment to
  240. * be used in the creation of the state factory and
  241. * the object's state.
  242. * @param attrs The possibly null Attributes that is to be bound with the
  243. * object.
  244. * @return A non-null DirStateFactory.Result containing
  245. * the object and attributes to be bound.
  246. * If no state factory returns a non-null answer, the result will contain
  247. * the object (<tt>obj</tt>) itself with the original attributes.
  248. * @exception NamingException If a naming exception was encountered
  249. * while using the factories.
  250. * A factory should only throw an exception if it does not want
  251. * other factories to be used in an attempt to create an object.
  252. * See <tt>DirStateFactory.getStateToBind()</tt>.
  253. * @see DirStateFactory
  254. * @see DirStateFactory#getStateToBind
  255. * @see NamingManager#getStateToBind
  256. * @since 1.3
  257. */
  258. public static DirStateFactory.Result
  259. getStateToBind(Object obj, Name name, Context nameCtx,
  260. Hashtable environment, Attributes attrs)
  261. throws NamingException {
  262. // Get list of state factories
  263. FactoryEnumeration factories = ResourceManager.getFactories(
  264. Context.STATE_FACTORIES, environment, nameCtx);
  265. if (factories == null) {
  266. // no factories to try; just return originals
  267. return new DirStateFactory.Result(obj, attrs);
  268. }
  269. // Try each factory until one succeeds
  270. StateFactory factory;
  271. Object objanswer;
  272. DirStateFactory.Result answer = null;
  273. while (answer == null && factories.hasMore()) {
  274. factory = (StateFactory)factories.next();
  275. if (factory instanceof DirStateFactory) {
  276. answer = ((DirStateFactory)factory).
  277. getStateToBind(obj, name, nameCtx, environment, attrs);
  278. } else {
  279. objanswer =
  280. factory.getStateToBind(obj, name, nameCtx, environment);
  281. if (objanswer != null) {
  282. answer = new DirStateFactory.Result(objanswer, attrs);
  283. }
  284. }
  285. }
  286. return (answer != null) ? answer :
  287. new DirStateFactory.Result(obj, attrs); // nothing new
  288. }
  289. }