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 }