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