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