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 }