001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * docs/licenses/cddl.txt. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2011-2012 UnboundID Corp.
026 */
027 package com.unboundid.directory.sdk.http.api;
028
029
030
031 import java.util.Collections;
032 import java.util.List;
033 import java.util.Map;
034
035 import javax.servlet.Filter;
036 import javax.servlet.http.HttpServlet;
037
038 import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
039 import com.unboundid.directory.sdk.common.internal.Reconfigurable;
040 import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
041 import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
042 import com.unboundid.directory.sdk.http.config.HTTPServletExtensionConfig;
043 import com.unboundid.directory.sdk.http.types.HTTPServerContext;
044 import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
045 import com.unboundid.ldap.sdk.LDAPException;
046 import com.unboundid.ldap.sdk.ResultCode;
047 import com.unboundid.util.Extensible;
048 import com.unboundid.util.ThreadSafety;
049 import com.unboundid.util.ThreadSafetyLevel;
050 import com.unboundid.util.args.ArgumentException;
051 import com.unboundid.util.args.ArgumentParser;
052
053
054
055 /**
056 * This class defines an API that must be implemented by extensions which create
057 * servlets for use with an HTTP connection handler.
058 * <BR>
059 * <H2>Configuring HTTP Servlet Extensions</H2>
060 * In order to configure an HTTP servlet extension created using this API, use a
061 * command like:
062 * <PRE>
063 * dsconfig create-http-servlet-extension \
064 * --extension-name "<I>{extension-name}</I>" \
065 * --type third-party \
066 * --set enabled:true \
067 * --set "extension-class:<I>{class-name}</I>" \
068 * --set "extension-argument:<I>{name=value}</I>"
069 * </PRE>
070 * where "<I>{extension-name}</I>" is the name to use for the HTTP servlet
071 * extension instance, "<I>{class-name}</I>" is the fully-qualified name of the
072 * Java class that extends
073 * {@code com.unboundid.directory.sdk.ds.api.HTTPServletExtension},
074 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
075 * provide to the HTTP servlet extension. If multiple arguments should be
076 * provided to the HTTP servlet extension, then the
077 * "<CODE>--set extension-argument:<I>{name=value}</I></CODE>" option should be
078 * provided multiple times.
079 *
080 * @see com.unboundid.directory.sdk.http.scripting.ScriptedHTTPServletExtension
081 */
082 @Extensible()
083 @DirectoryServerExtension()
084 @DirectoryProxyServerExtension(appliesToLocalContent=true,
085 appliesToRemoteContent=true)
086 @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
087 public abstract class HTTPServletExtension
088 implements UnboundIDExtension,
089 Reconfigurable<HTTPServletExtensionConfig>,
090 ExampleUsageProvider
091 {
092 /**
093 * Creates a new instance of this HTTP servlet extension. All HTTP servlet
094 * extension implementations must include a default constructor, but any
095 * initialization should generally be done in the
096 * {@code createServlet} method.
097 */
098 public HTTPServletExtension()
099 {
100 // No implementation is required.
101 }
102
103
104
105 /**
106 * {@inheritDoc}
107 */
108 public abstract String getExtensionName();
109
110
111
112 /**
113 * {@inheritDoc}
114 */
115 public abstract String[] getExtensionDescription();
116
117
118
119 /**
120 * {@inheritDoc}
121 */
122 public void defineConfigArguments(final ArgumentParser parser)
123 throws ArgumentException
124 {
125 // No arguments will be allowed by default.
126 }
127
128
129
130 /**
131 * {@inheritDoc}
132 */
133 public boolean isConfigurationAcceptable(
134 final HTTPServletExtensionConfig config,
135 final ArgumentParser parser,
136 final List<String> unacceptableReasons)
137 {
138 // No extended validation will be performed by default.
139 return true;
140 }
141
142
143
144 /**
145 * {@inheritDoc}
146 */
147 public ResultCode applyConfiguration(final HTTPServletExtensionConfig config,
148 final ArgumentParser parser,
149 final List<String> adminActionsRequired,
150 final List<String> messages)
151 {
152 // By default, no configuration changes will be applied. If there are any
153 // arguments, then add an admin action message indicating that the extension
154 // needs to be restarted for any changes to take effect.
155 if (! parser.getNamedArguments().isEmpty())
156 {
157 adminActionsRequired.add(
158 "No configuration change has actually been applied. The new " +
159 "configuration will not take effect until this HTTP servlet " +
160 "extension is disabled and re-enabled or until the server is " +
161 "restarted.");
162 }
163
164 return ResultCode.SUCCESS;
165 }
166
167
168
169 /**
170 * {@inheritDoc}
171 */
172 public Map<List<String>,String> getExamplesArgumentSets()
173 {
174 return Collections.emptyMap();
175 }
176
177
178
179 /**
180 * Creates an HTTP servlet extension using the provided information.
181 *
182 * @param serverContext A handle to the server context for the server in
183 * which this extension is running.
184 * @param config The general configuration for this HTTP servlet
185 * extension.
186 * @param parser The argument parser which has been initialized from
187 * the configuration for this HTTP servlet extension.
188 *
189 * @return The HTTP servlet that has been created.
190 *
191 * @throws LDAPException If a problem is encountered while attempting to
192 * create the HTTP servlet.
193 */
194 public abstract HttpServlet createServlet(
195 final HTTPServerContext serverContext,
196 final HTTPServletExtensionConfig config,
197 final ArgumentParser parser)
198 throws LDAPException;
199
200
201
202 /**
203 * Retrieves a list of the request paths for which the associated servlet
204 * should be invoked. This method will be called after the
205 * {@link #createServlet} method has been used to create the servlet instance.
206 *
207 * @return A list of the request paths for which the associated servlet
208 * should be invoked.
209 */
210 public abstract List<String> getServletPaths();
211
212
213
214 /**
215 * Retrieves a map of initialization parameters that should be provided to the
216 * servlet when it is initialized.
217 *
218 * @return A map of initialization parameters that should be provided to the
219 * servlet when it is initialized, or an empty map if no
220 * initialization parameters are needed.
221 */
222 public Map<String,String> getServletInitParameters()
223 {
224 return Collections.emptyMap();
225 }
226
227
228
229 /**
230 * Retrieves the order in which the servlet should be started. A value
231 * greater than or equal to zero guarantees that the servlet will be started
232 * as soon as the servlet engine has been started, in order of ascending
233 * servlet init order values, before the {@code doPostRegistrationProcessing}
234 * method has been called. If the value is less than zero, the servlet may
235 * not be started until a request is received for one of its registered paths.
236 *
237 * @return The order in which the servlet should be started, or a negative
238 * value if startup order does not matter.
239 */
240 public int getServletInitOrder()
241 {
242 return -1;
243 }
244
245
246
247 /**
248 * Retrieves a list of servlet filter instances that should be installed with
249 * the created servlet instance, in the order they should be invoked. If the
250 * servlet is to be registered with multiple paths, then these filters will be
251 * installed for all of those paths.
252 *
253 * @return A list of servlet filter instances that should be installed with
254 * the created servlet instance, in the order that they should be
255 * invoked. It may be {@code null} or empty if no servlet filters
256 * should be installed.
257 */
258 public List<Filter> getServletFilters()
259 {
260 return Collections.emptyList();
261 }
262
263
264
265 /**
266 * Performs any processing that may be needed after the servlet has been
267 * registered with the servlet engine. If the value returned from
268 * {@link #getServletInitOrder()} is greater than or equal to zero, then the
269 * servlet will have been started before this method is called. If the value
270 * returned from {@code getServletInitOrder()} is negative, then the servlet
271 * may or may not have been started by the time this method is called.
272 * <BR><BR>
273 * Note that the associated servlet can also perform any necessary
274 * initialization processing in the {@code init} method provided by the
275 * servlet API.
276 */
277 public void doPostRegistrationProcessing()
278 {
279 // No implementation required by default.
280 }
281
282
283
284 /**
285 * Performs any processing that may be needed after the servlet has been
286 * taken out of service and the associated servlet engine has been shut down.
287 * <BR><BR>
288 * Note that the associated servlet can also perform any necessary
289 * finalization processing in the {@code destroy} method provided by the
290 * servlet API. That method will be called after the servlet has been taken
291 * out of service, but before the servlet engine has been shut down.
292 */
293 public void doPostShutdownProcessing()
294 {
295 // No implementation required by default.
296 }
297 }