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 }