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