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