1 /* 2 * Copyright (c) 1999, 2020, 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.ldap; 27 28 import javax.naming.NamingException; 29 import javax.naming.Context; 30 31 import java.util.Hashtable; 32 33 import com.sun.naming.internal.FactoryEnumeration; 34 import com.sun.naming.internal.ResourceManager; 35 36 37 /** 38 * This abstract class represents a factory for creating LDAPv3 controls. 39 * LDAPv3 controls are defined in 40 * <A HREF="http://www.ietf.org/rfc/rfc2251.txt">RFC 2251</A>. 41 *<p> 42 * When a service provider receives a response control, it uses control 43 * factories to return the specific/appropriate control class implementation. 44 * 45 * @author Rosanna Lee 46 * @author Scott Seligman 47 * @author Vincent Ryan 48 * 49 * @see Control 50 * @since 1.3 51 */ 52 53 public abstract class ControlFactory { 54 /** 55 * Creates a new instance of a control factory. 56 */ ControlFactory()57 protected ControlFactory() { 58 } 59 60 /** 61 * Creates a control using this control factory. 62 *<p> 63 * The factory is used by the service provider to return controls 64 * that it reads from the LDAP protocol as specialized control classes. 65 * Without this mechanism, the provider would be returning 66 * controls that only contained data in BER encoded format. 67 *<p> 68 * Typically, {@code ctl} is a "basic" control containing 69 * BER encoded data. The factory is used to create a specialized 70 * control implementation, usually by decoding the BER encoded data, 71 * that provides methods to access that data in a type-safe and friendly 72 * manner. 73 * <p> 74 * For example, a factory might use the BER encoded data in 75 * basic control and return an instance of a VirtualListReplyControl. 76 *<p> 77 * If this factory cannot create a control using the argument supplied, 78 * it should return null. 79 * A factory should only throw an exception if it is sure that 80 * it is the only intended factory and that no other control factories 81 * should be tried. This might happen, for example, if the BER data 82 * in the control does not match what is expected of a control with 83 * the given OID. Since this method throws {@code NamingException}, 84 * any other internally generated exception that should be propagated 85 * must be wrapped inside a {@code NamingException}. 86 * 87 * @param ctl A non-null control. 88 * 89 * @return A possibly null Control. 90 * @throws NamingException If {@code ctl} contains invalid data that prevents it 91 * from being used to create a control. A factory should only throw 92 * an exception if it knows how to produce the control (identified by the OID) 93 * but is unable to because of, for example invalid BER data. 94 */ getControlInstance(Control ctl)95 public abstract Control getControlInstance(Control ctl) throws NamingException; 96 97 /** 98 * Creates a control using known control factories. 99 * <p> 100 * The following rule is used to create the control: 101 *<ul> 102 * <li> Use the control factories specified in 103 * the {@code LdapContext.CONTROL_FACTORIES} property of the 104 * environment, and of the provider resource file associated with 105 * {@code ctx}, in that order. 106 * The value of this property is a colon-separated list of factory 107 * class names that are tried in order, and the first one that succeeds 108 * in creating the control is the one used. 109 * If none of the factories can be loaded, 110 * return {@code ctl}. 111 * If an exception is encountered while creating the control, the 112 * exception is passed up to the caller. 113 *</ul> 114 * <p> 115 * Note that a control factory must be public and must have a public 116 * constructor that accepts no arguments. 117 * In cases where the factory is in a named module then it must be in a 118 * package which is exported by that module to the {@code java.naming} 119 * module. 120 * 121 * @param ctl The non-null control object containing the OID and BER data. 122 * @param ctx The possibly null context in which the control is being created. 123 * If null, no such information is available. 124 * @param env The possibly null environment of the context. This is used 125 * to find the value of the {@code LdapContext.CONTROL_FACTORIES} property. 126 * @return A control object created using {@code ctl}; or 127 * {@code ctl} if a control object cannot be created using 128 * the algorithm described above. 129 * @throws NamingException if a naming exception was encountered 130 * while attempting to create the control object. 131 * If one of the factories accessed throws an 132 * exception, it is propagated up to the caller. 133 * If an error was encountered while loading 134 * and instantiating the factory and object classes, the exception 135 * is wrapped inside a {@code NamingException} and then rethrown. 136 */ getControlInstance(Control ctl, Context ctx, Hashtable<?,?> env)137 public static Control getControlInstance(Control ctl, Context ctx, 138 Hashtable<?,?> env) 139 throws NamingException { 140 141 // Get object factories list from environment properties or 142 // provider resource file. 143 FactoryEnumeration factories = ResourceManager.getFactories( 144 LdapContext.CONTROL_FACTORIES, env, ctx); 145 146 if (factories == null) { 147 return ctl; 148 } 149 150 // Try each factory until one succeeds 151 Control answer = null; 152 ControlFactory factory; 153 while (answer == null && factories.hasMore()) { 154 factory = (ControlFactory)factories.next(); 155 answer = factory.getControlInstance(ctl); 156 } 157 158 return (answer != null)? answer : ctl; 159 } 160 } 161