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.scripting;
028
029
030
031 import java.util.List;
032 import java.util.Map;
033
034 import javax.servlet.http.HttpServletRequest;
035 import javax.servlet.http.HttpServletResponse;
036
037 import com.unboundid.directory.sdk.common.internal.Reconfigurable;
038 import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
039 import com.unboundid.directory.sdk.http.config.HTTPOperationLoggerConfig;
040 import com.unboundid.directory.sdk.http.types.HTTPServerContext;
041 import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
042 import com.unboundid.ldap.sdk.LDAPException;
043 import com.unboundid.ldap.sdk.ResultCode;
044 import com.unboundid.util.Extensible;
045 import com.unboundid.util.ThreadSafety;
046 import com.unboundid.util.ThreadSafetyLevel;
047 import com.unboundid.util.args.ArgumentException;
048 import com.unboundid.util.args.ArgumentParser;
049
050
051
052 /**
053 * This class defines an API that must be implemented by extensions which
054 * record information about interaction with HTTP clients. Scripted HTTP
055 * operation loggers may write information to files, but they may also write to
056 * other locations, including databases, message, queues, e-mail messages, or
057 * other targets.
058 * <BR>
059 * <H2>Configuring Scripted HTTP Operation Loggers</H2>
060 * In order to configure a scripted HTTP operation logger created using this
061 * API, use a command like:
062 * <PRE>
063 * dsconfig create-log-publisher \
064 * --publisher-name "<I>{logger-name}</I>" \
065 * --type groovy-scripted-http-operation \
066 * --set enabled:true \
067 * --set "script-class:<I>{class-name}</I>" \
068 * --set "script-argument:<I>{name=value}</I>"
069 * </PRE>
070 * where "<I>{logger-name}</I>" is the name to use for the scripted HTTP
071 * operation logger instance, "<I>{script-class}</I>" is the fully-qualified
072 * name of the Groovy class written using this API, and "<I>{name=value}</I>"
073 * represents name-value pairs for any arguments to provide to the logger. If
074 * multiple arguments should be provided to the logger, then the
075 * "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be
076 * provided multiple times.
077 *
078 * @see com.unboundid.directory.sdk.http.api.HTTPOperationLogger
079 */
080 @Extensible()
081 @DirectoryServerExtension()
082 @DirectoryProxyServerExtension(appliesToLocalContent=true,
083 appliesToRemoteContent=true)
084 @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
085 public abstract class ScriptedHTTPOperationLogger
086 implements Reconfigurable<HTTPOperationLoggerConfig>
087 {
088 /**
089 * The key that will be used to hold the time the request was received, in
090 * milliseconds since January 1, 1960, UTC, as reported by
091 * {@code System.currentTimeMillis()}. It will always be present in the state
092 * map when the {@link #logResponse} method is invoked. The value associated
093 * with this key will be a {@code java.lang.Long} object.
094 */
095 public static final String STATE_KEY_REQUEST_TIME_MILLIS =
096 "___request_time_millis___";
097
098
099
100 /**
101 * The key that will be used to hold the response content length in the state
102 * map. It will always be present in the state map when the
103 * {@link #logResponse} method is invoked. The value associated with this key
104 * will be a {@code java.lang.Long} object.
105 */
106 public static final String STATE_KEY_RESPONSE_CONTENT_LENGTH =
107 "___response_content_length___";
108
109
110
111 /**
112 * The key that will be used to hold the operation processing time in
113 * milliseconds. It will always be present in the state map when the
114 * {@link #logResponse} method is invoked. The value associated with this key
115 * will be a {@code java.lang.Long} object.
116 */
117 public static final String STATE_KEY_PROCESSING_TIME_MILLIS =
118 "___processing_time_millis___";
119
120
121
122 /**
123 * The key that will be used to hold the operation processing time in
124 * nanoseconds. It will always be present in the state map when the
125 * {@link #logResponse} method is invoked. The value associated with this key
126 * will be a {@code java.lang.Long} object.
127 */
128 public static final String STATE_KEY_PROCESSING_TIME_NANOS =
129 "___processing_time_nanos___";
130
131
132
133 /**
134 * Creates a new instance of this scripted HTTP operation logger. All
135 * scripted HTTP operation logger implementations must include a default
136 * constructor, but any initialization should generally be done in the
137 * {@code initializeHTTPOperationLogger} method.
138 */
139 public ScriptedHTTPOperationLogger()
140 {
141 // No implementation is required.
142 }
143
144
145
146 /**
147 * {@inheritDoc}
148 */
149 public void defineConfigArguments(final ArgumentParser parser)
150 throws ArgumentException
151 {
152 // No arguments will be allowed by default.
153 }
154
155
156
157 /**
158 * Initializes this scripted HTTP operation logger.
159 *
160 * @param serverContext A handle to the server context for the server in
161 * which this extension is running.
162 * @param config The general configuration for this HTTP operation
163 * logger.
164 * @param parser The argument parser which has been initialized from
165 * the configuration for this HTTP operation logger.
166 *
167 * @throws LDAPException If a problem occurs while initializing this HTTP
168 * operation logger.
169 */
170 public void initializeHTTPOperationLogger(
171 final HTTPServerContext serverContext,
172 final HTTPOperationLoggerConfig config,
173 final ArgumentParser parser)
174 throws LDAPException
175 {
176 // No initialization will be performed by default.
177 }
178
179
180
181 /**
182 * {@inheritDoc}
183 */
184 public boolean isConfigurationAcceptable(
185 final HTTPOperationLoggerConfig config,
186 final ArgumentParser parser,
187 final List<String> unacceptableReasons)
188 {
189 // No extended validation will be performed by default.
190 return true;
191 }
192
193
194
195 /**
196 * {@inheritDoc}
197 */
198 public ResultCode applyConfiguration(final HTTPOperationLoggerConfig config,
199 final ArgumentParser parser,
200 final List<String> adminActionsRequired,
201 final List<String> messages)
202 {
203 // By default, no configuration changes will be applied. If there are any
204 // arguments, then add an admin action message indicating that the extension
205 // needs to be restarted for any changes to take effect.
206 if (! parser.getNamedArguments().isEmpty())
207 {
208 adminActionsRequired.add(
209 "No configuration change has actually been applied. The new " +
210 "configuration will not take effect until this scripted HTTP " +
211 "operation logger is disabled and re-enabled or until the " +
212 "server is restarted.");
213 }
214
215 return ResultCode.SUCCESS;
216 }
217
218
219
220 /**
221 * Performs any cleanup which may be necessary when this HTTP operation logger
222 * is to be taken out of service.
223 */
224 public void finalizeHTTPOperationLogger()
225 {
226 // No implementation is required.
227 }
228
229
230
231 /**
232 * Logs information about a servlet request that has been received from the
233 * client.
234 *
235 * @param request An object with information about the request received
236 * from the client.
237 * @param stateMap An empty map which may be updated to hold state
238 * information that can be used to correlate information
239 * between the request and response. The same map instance
240 * will be passed to the {@link #logResponse} method.
241 */
242 public void logRequest(final HttpServletRequest request,
243 final Map<String,Object> stateMap)
244 {
245 // No processing performed by default.
246 }
247
248
249
250 /**
251 * Logs information about a servlet response to be returned to the client.
252 *
253 * @param request An object with information about the request received
254 * from the client.
255 * @param response An object with information about the response to be
256 * returned to the client.
257 * @param stateMap A map containing state any information added while
258 * processing the {@link #logRequest} method.
259 */
260 public void logResponse(final HttpServletRequest request,
261 final HttpServletResponse response,
262 final Map<String,Object> stateMap)
263 {
264 // No processing performed by default.
265 }
266 }