1 /*
2 * Copyright 1999-2004 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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="ftp://ftp.isi.edu/in-notes/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 */
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, <tt>ctl</tt> 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 <tt>NamingException</tt>,
84 * any other internally generated exception that should be propagated
85 * must be wrapped inside a <tt>NamingException</tt>.
86 *
87 * @param ctl A non-null control.
88 *
89 * @return A possibly null Control.
90 * @exception NamingException If <tt>ctl</tt> 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 */
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 <tt>LdapContext.CONTROL_FACTORIES</tt> property of the
104 * environment, and of the provider resource file associated with
105 * <tt>ctx</tt>, 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</code>.
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
116 * must be public and must have a public constructor that accepts no arguments.
117 * <p>
118 * @param ctl The non-null control object containing the OID and BER data.
119 * @param ctx The possibly null context in which the control is being created.
120 * If null, no such information is available.
121 * @param env The possibly null environment of the context. This is used
122 * to find the value of the <tt>LdapContext.CONTROL_FACTORIES</tt> property.
123 * @return A control object created using <code>ctl</code>; or
124 * <code>ctl</code> if a control object cannot be created using
125 * the algorithm described above.
126 * @exception NamingException if a naming exception was encountered
127 * while attempting to create the control object.
128 * If one of the factories accessed throws an
129 * exception, it is propagated up to the caller.
130 * If an error was encountered while loading
131 * and instantiating the factory and object classes, the exception
132 * is wrapped inside a <tt>NamingException</tt> and then rethrown.
133 */
134 public static Control getControlInstance(Control ctl, Context ctx,
135 Hashtable<?,?> env)
136 throws NamingException {
137
138 // Get object factories list from environment properties or
139 // provider resource file.
140 FactoryEnumeration factories = ResourceManager.getFactories(
141 LdapContext.CONTROL_FACTORIES, env, ctx);
142
143 if (factories == null) {
144 return ctl;
145 }
146
147 // Try each factory until one succeeds
148 Control answer = null;
149 ControlFactory factory;
150 while (answer == null && factories.hasMore()) {
151 factory = (ControlFactory)factories.next();
152 answer = factory.getControlInstance(ctl);
153 }
154
155 return (answer != null)? answer : ctl;
156 }
157 }