1 /* 2 * Copyright (c) 1999, 2012, 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 @SuppressWarnings("unchecked") 88 public static DirContext getContinuationDirContext( 89 CannotProceedException cpe) throws NamingException { 90 91 Hashtable<Object,Object> env = (Hashtable<Object,Object>)cpe.getEnvironment(); 92 if (env == null) { 93 env = new Hashtable<>(7); 94 } else { 95 // Make a (shallow) copy of the environment. 96 env = env.clone(); 97 } 98 env.put(CPE, cpe); 99 100 return (new ContinuationDirContext(cpe, env)); 101 } 102 103 /** 104 * Creates an instance of an object for the specified object, 105 * attributes, and environment. 106 * <p> 107 * This method is the same as <tt>NamingManager.getObjectInstance</tt> 108 * except for the following differences: 109 *<ul> 110 *<li> 111 * It accepts an <tt>Attributes</tt> parameter that contains attributes 112 * associated with the object. The <tt>DirObjectFactory</tt> might use these 113 * attributes to save having to look them up from the directory. 114 *<li> 115 * The object factories tried must implement either 116 * <tt>ObjectFactory</tt> or <tt>DirObjectFactory</tt>. 117 * If it implements <tt>DirObjectFactory</tt>, 118 * <tt>DirObjectFactory.getObjectInstance()</tt> is used, otherwise, 119 * <tt>ObjectFactory.getObjectInstance()</tt> is used. 120 *</ul> 121 * Service providers that implement the <tt>DirContext</tt> interface 122 * should use this method, not <tt>NamingManager.getObjectInstance()</tt>. 123 *<p> 124 * 125 * @param refInfo The possibly null object for which to create an object. 126 * @param name The name of this object relative to <code>nameCtx</code>. 127 * Specifying a name is optional; if it is 128 * omitted, <code>name</code> should be null. 129 * @param nameCtx The context relative to which the <code>name</code> 130 * parameter is specified. If null, <code>name</code> is 131 * relative to the default initial context. 132 * @param environment The possibly null environment to 133 * be used in the creation of the object factory and the object. 134 * @param attrs The possibly null attributes associated with refInfo. 135 * This might not be the complete set of attributes for refInfo; 136 * you might be able to read more attributes from the directory. 137 * @return An object created using <code>refInfo</code> and <tt>attrs</tt>; or 138 * <code>refInfo</code> if an object cannot be created by 139 * a factory. 140 * @exception NamingException If a naming exception was encountered 141 * while attempting to get a URL context, or if one of the 142 * factories accessed throws a NamingException. 143 * @exception Exception If one of the factories accessed throws an 144 * exception, or if an error was encountered while loading 145 * and instantiating the factory and object classes. 146 * A factory should only throw an exception if it does not want 147 * other factories to be used in an attempt to create an object. 148 * See <tt>DirObjectFactory.getObjectInstance()</tt>. 149 * @see NamingManager#getURLContext 150 * @see DirObjectFactory 151 * @see DirObjectFactory#getObjectInstance 152 * @since 1.3 153 */ 154 public static Object 155 getObjectInstance(Object refInfo, Name name, Context nameCtx, 156 Hashtable<?,?> environment, Attributes attrs) 157 throws Exception { 158 159 ObjectFactory factory; 160 161 ObjectFactoryBuilder builder = getObjectFactoryBuilder(); 162 if (builder != null) { 163 // builder must return non-null factory 164 factory = builder.createObjectFactory(refInfo, environment); 165 if (factory instanceof DirObjectFactory) { 166 return ((DirObjectFactory)factory).getObjectInstance( 167 refInfo, name, nameCtx, environment, attrs); 168 } else { 169 return factory.getObjectInstance(refInfo, name, nameCtx, 170 environment); 171 } 172 } 173 174 // use reference if possible 175 Reference ref = null; 176 if (refInfo instanceof Reference) { 177 ref = (Reference) refInfo; 178 } else if (refInfo instanceof Referenceable) { 179 ref = ((Referenceable)(refInfo)).getReference(); 180 } 181 182 Object answer; 183 184 if (ref != null) { 185 String f = ref.getFactoryClassName(); 186 if (f != null) { 187 // if reference identifies a factory, use exclusively 188 189 factory = getObjectFactoryFromReference(ref, f); 190 if (factory instanceof DirObjectFactory) { 191 return ((DirObjectFactory)factory).getObjectInstance( 192 ref, name, nameCtx, environment, attrs); 193 } else if (factory != null) { 194 return factory.getObjectInstance(ref, name, nameCtx, 195 environment); 196 } 197 // No factory found, so return original refInfo. 198 // Will reach this point if factory class is not in 199 // class path and reference does not contain a URL for it 200 return refInfo; 201 202 } else { 203 // if reference has no factory, check for addresses 204 // containing URLs 205 // ignore name & attrs params; not used in URL factory 206 207 answer = processURLAddrs(ref, name, nameCtx, environment); 208 if (answer != null) { 209 return answer; 210 } 211 } 212 } 213 214 // try using any specified factories 215 answer = createObjectFromFactories(refInfo, name, nameCtx, 216 environment, attrs); 217 return (answer != null) ? answer : refInfo; 218 } 219 220 private static Object createObjectFromFactories(Object obj, Name name, 221 Context nameCtx, Hashtable<?,?> environment, Attributes attrs) 222 throws Exception { 223 224 FactoryEnumeration factories = ResourceManager.getFactories( 225 Context.OBJECT_FACTORIES, environment, nameCtx); 226 227 if (factories == null) 228 return null; 229 230 ObjectFactory factory; 231 Object answer = null; 232 // Try each factory until one succeeds 233 while (answer == null && factories.hasMore()) { 234 factory = (ObjectFactory)factories.next(); 235 if (factory instanceof DirObjectFactory) { 236 answer = ((DirObjectFactory)factory). 237 getObjectInstance(obj, name, nameCtx, environment, attrs); 238 } else { 239 answer = 240 factory.getObjectInstance(obj, name, nameCtx, environment); 241 } 242 } 243 return answer; 244 } 245 246 /** 247 * Retrieves the state of an object for binding when given the original 248 * object and its attributes. 249 * <p> 250 * This method is like <tt>NamingManager.getStateToBind</tt> except 251 * for the following differences: 252 *<ul> 253 *<li>It accepts an <tt>Attributes</tt> parameter containing attributes 254 * that were passed to the <tt>DirContext.bind()</tt> method. 255 *<li>It returns a non-null <tt>DirStateFactory.Result</tt> instance 256 * containing the object to be bound, and the attributes to 257 * accompany the binding. Either the object or the attributes may be null. 258 *<li> 259 * The state factories tried must each implement either 260 * <tt>StateFactory</tt> or <tt>DirStateFactory</tt>. 261 * If it implements <tt>DirStateFactory</tt>, then 262 * <tt>DirStateFactory.getStateToBind()</tt> is called; otherwise, 263 * <tt>StateFactory.getStateToBind()</tt> is called. 264 *</ul> 265 * 266 * Service providers that implement the <tt>DirContext</tt> interface 267 * should use this method, not <tt>NamingManager.getStateToBind()</tt>. 268 *<p> 269 * See NamingManager.getStateToBind() for a description of how 270 * the list of state factories to be tried is determined. 271 *<p> 272 * The object returned by this method is owned by the caller. 273 * The implementation will not subsequently modify it. 274 * It will contain either a new <tt>Attributes</tt> object that is 275 * likewise owned by the caller, or a reference to the original 276 * <tt>attrs</tt> parameter. 277 * 278 * @param obj The non-null object for which to get state to bind. 279 * @param name The name of this object relative to <code>nameCtx</code>, 280 * or null if no name is specified. 281 * @param nameCtx The context relative to which the <code>name</code> 282 * parameter is specified, or null if <code>name</code> is 283 * relative to the default initial context. 284 * @param environment The possibly null environment to 285 * be used in the creation of the state factory and 286 * the object's state. 287 * @param attrs The possibly null Attributes that is to be bound with the 288 * object. 289 * @return A non-null DirStateFactory.Result containing 290 * the object and attributes to be bound. 291 * If no state factory returns a non-null answer, the result will contain 292 * the object (<tt>obj</tt>) itself with the original attributes. 293 * @exception NamingException If a naming exception was encountered 294 * while using the factories. 295 * A factory should only throw an exception if it does not want 296 * other factories to be used in an attempt to create an object. 297 * See <tt>DirStateFactory.getStateToBind()</tt>. 298 * @see DirStateFactory 299 * @see DirStateFactory#getStateToBind 300 * @see NamingManager#getStateToBind 301 * @since 1.3 302 */ 303 public static DirStateFactory.Result 304 getStateToBind(Object obj, Name name, Context nameCtx, 305 Hashtable<?,?> environment, Attributes attrs) 306 throws NamingException { 307 308 // Get list of state factories 309 FactoryEnumeration factories = ResourceManager.getFactories( 310 Context.STATE_FACTORIES, environment, nameCtx); 311 312 if (factories == null) { 313 // no factories to try; just return originals 314 return new DirStateFactory.Result(obj, attrs); 315 } 316 317 // Try each factory until one succeeds 318 StateFactory factory; 319 Object objanswer; 320 DirStateFactory.Result answer = null; 321 while (answer == null && factories.hasMore()) { 322 factory = (StateFactory)factories.next(); 323 if (factory instanceof DirStateFactory) { 324 answer = ((DirStateFactory)factory). 325 getStateToBind(obj, name, nameCtx, environment, attrs); 326 } else { 327 objanswer = 328 factory.getStateToBind(obj, name, nameCtx, environment); 329 if (objanswer != null) { 330 answer = new DirStateFactory.Result(objanswer, attrs); 331 } 332 } 333 } 334 335 return (answer != null) ? answer : 336 new DirStateFactory.Result(obj, attrs); // nothing new 337 } 338 }