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 2017 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.common.api;
028
029
030
031import java.util.Collections;
032import java.util.List;
033import java.util.Map;
034
035import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
036import com.unboundid.directory.sdk.common.config.HTTPTraceLoggerConfig;
037import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
038import com.unboundid.directory.sdk.common.internal.Reconfigurable;
039import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
040import com.unboundid.directory.sdk.common.types.ServerContext;
041import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
042import com.unboundid.directory.sdk.metrics.internal.MetricsEngineExtension;
043import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
044import com.unboundid.ldap.sdk.LDAPException;
045import com.unboundid.ldap.sdk.ResultCode;
046import com.unboundid.util.Extensible;
047import com.unboundid.util.ThreadSafety;
048import com.unboundid.util.ThreadSafetyLevel;
049import com.unboundid.util.args.ArgumentException;
050import com.unboundid.util.args.ArgumentParser;
051import javax.servlet.http.HttpServletRequest;
052
053
054/**
055 * This class defines an API that must be implemented by extensions which
056 * record information about HTTP operations in the server.
057 * <BR><BR>
058 * Each trace logger may be configured to indicate whether to include or
059 * exclude log messages based on a set of target message types.  Nothing is
060 * logged by a trace logger unless it is configured with one or more message
061 * types to log.  Filtering by message type is handled automatically by the
062 * server, so individual trace logger implementations do not need to attempt to
063 * perform that filtering on their own.  However, they may perform additional
064 * processing if desired to further narrow the set of messages that should be
065 * logged.
066 * <BR>
067 * <H2>Configuring Trace Loggers</H2>
068 * In order to configure a trace logger created using this API, use a command
069 * like:
070 * <PRE>
071 *      dsconfig create-log-publisher \
072 *           --publisher-name "<I>{logger-name}</I>" \
073 *           --type third-party-http-trace \
074 *           --set enabled:true \
075 *           --set "extension-class:<I>{class-name}</I>" \
076 *           --set "extension-argument:<I>{name=value}</I>"
077 * </PRE>
078 * where "<I>{logger-name}</I>" is the name to use for the trace logger
079 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Java class
080 * that extends {@code com.unboundid.directory.sdk.common.api.TraceLogger},
081 * and "<I>{name=value}</I>" represents name-value pairs for any arguments to
082 * provide to the logger.  If multiple arguments should be provided to the
083 * logger, then the "<CODE>--set extension-argument:<I>{name=value}</I></CODE>"
084 * option should be provided multiple times.
085 */
086@Extensible()
087@DirectoryServerExtension()
088@DirectoryProxyServerExtension(appliesToLocalContent=true,
089     appliesToRemoteContent=true)
090@MetricsEngineExtension()
091@BrokerExtension()
092@ThreadSafety(level= ThreadSafetyLevel.INTERFACE_THREADSAFE)
093public abstract class HTTPTraceLogger
094       implements UnboundIDExtension, Reconfigurable<HTTPTraceLoggerConfig>,
095                  ExampleUsageProvider
096{
097  /**
098   * The servlet request key that will be used to hold the request resource
099   * for SCIM create requests (messageCategory = "SCIM",
100   * messageType = "REQUEST", keyValues["op"] = "CREATE"). This will be an
101   * instance of {@code com.unboundid.scim2.common.GenericScimResource} or
102   * {@code null} if this is not a SCIM create request.
103   */
104  public static final String ATTRIBUTE_KEY_CREATE_REQUEST_RESOURCE =
105       "scim_create_request_resource";
106
107  /**
108   * The servlet request key that will be used to hold the request resource
109   * for SCIM create requests (messageCategory = "SCIM", messageType = "RESULT",
110   * keyValues["op"] = "CREATE"). This will be an instance of
111   * {@code com.unboundid.scim2.common.GenericScimResource} or {@code null}
112   * if this is not a SCIM create result.
113   */
114  public static final String ATTRIBUTE_KEY_CREATE_RESULT_RESOURCE =
115       "scim_create_result_resource";
116
117  /**
118   * The servlet request key that will be used to hold the request resource
119   * for SCIM modify requests using PUT (messageCategory = "SCIM",
120   * messageType = "REQUEST", keyValues["op"] = "MODIFY"). This will be an
121   * instance of {@code com.unboundid.scim2.common.GenericScimResource} or
122   * {@code null} if this is not a SCIM modify request using PUT.
123   */
124  public static final String ATTRIBUTE_KEY_REPLACE_REQUEST_RESOURCE =
125       "scim_replace_request_resource";
126
127  /**
128   * The servlet request key that will be used to hold the request resource
129   * for SCIM modify requests using PATCH (messageCategory = "SCIM",
130   * messageType = "REQUEST", keyValues["op"] = "MODIFY"). This will be an
131   * instance of {@code com.unboundid.scim2.common.messages.PatchRequest} or
132   * {@code null} if this is not a SCIM modify request using PATCH.
133   */
134  public static final String ATTRIBUTE_KEY_PATCH_REQUEST_RESOURCE =
135       "scim_patch_request_resource";
136
137  /**
138   * The servlet request key that will be used to hold the result resource
139   * for SCIM modify requests (messageCategory = "SCIM", messageType = "RESULT",
140   * keyValues["op"] = "MODIFY"). This will be an instance of
141   * {@code com.unboundid.scim2.common.GenericScimResource} or {@code null}
142   * if this is not a SCIM modify result.
143   */
144  public static final String ATTRIBUTE_KEY_MODIFY_RESULT_RESOURCE =
145       "scim_modify_result_resource";
146
147  /**
148   * Creates a new instance of this trace logger.  All trace logger
149   * implementations must include a default constructor, but any initialization
150   * should generally be done in the {@code initializeTraceLogger} method.
151   */
152  public HTTPTraceLogger()
153  {
154    // No implementation is required.
155  }
156
157
158
159  /**
160   * {@inheritDoc}
161   */
162  public abstract String getExtensionName();
163
164
165
166  /**
167   * {@inheritDoc}
168   */
169  public abstract String[] getExtensionDescription();
170
171
172
173  /**
174   * {@inheritDoc}
175   */
176  public void defineConfigArguments(final ArgumentParser parser)
177          throws ArgumentException
178  {
179    // No arguments will be allowed by default.
180  }
181
182
183
184  /**
185   * Initializes this trace logger.
186   *
187   * @param  serverContext  A handle to the server context for the server in
188   *                        which this extension is running.
189   * @param  config         The general configuration for this trace logger.
190   * @param  parser         The argument parser which has been initialized from
191   *                        the configuration for this trace logger.
192   *
193   * @throws LDAPException  If a problem occurs while initializing this trace
194   *                         logger.
195   */
196  public void initializeTraceLogger(final ServerContext serverContext,
197                                    final HTTPTraceLoggerConfig config,
198                                    final ArgumentParser parser)
199         throws LDAPException
200  {
201    // No initialization will be performed by default.
202  }
203
204
205
206  /**
207   * {@inheritDoc}
208   */
209  public boolean isConfigurationAcceptable(final HTTPTraceLoggerConfig config,
210                      final ArgumentParser parser,
211                      final List<String> unacceptableReasons)
212  {
213    // No extended validation will be performed by default.
214    return true;
215  }
216
217
218
219  /**
220   * {@inheritDoc}
221   */
222  public ResultCode applyConfiguration(final HTTPTraceLoggerConfig config,
223                                       final ArgumentParser parser,
224                                       final List<String> adminActionsRequired,
225                                       final List<String> messages)
226  {
227    // By default, no configuration changes will be applied.  If there are any
228    // arguments, then add an admin action message indicating that the extension
229    // needs to be restarted for any changes to take effect.
230    if (! parser.getNamedArguments().isEmpty())
231    {
232      adminActionsRequired.add(
233           "No configuration change has actually been applied.  The new " +
234                "configuration will not take effect until this trace logger " +
235                "is disabled and re-enabled or until the server is restarted.");
236    }
237
238    return ResultCode.SUCCESS;
239  }
240
241
242
243  /**
244   * Performs any cleanup which may be necessary when this trace logger is to
245   * be taken out of service.
246   */
247  public void finalizeTraceLogger()
248  {
249    // No implementation is required.
250  }
251
252
253
254  /**
255   * Writes a message to the trace log using the provided information. The
256   * provided message type will be used to determine whether to actually log
257   * this message.
258   *
259   * @param request
260   *          An object with information about the request received from the
261   *          client.
262   * @param messageCategory
263   *          The category of the logged message; never {@code null}.
264   *          The set of categories corresponds with the Trace Log Publisher
265   *          configuration object properties ending in -message-type, without
266   *          the suffix in all upper case with no dashes, for example
267   *          'XACMLPOLICY'. See dsconfig or the Console for the set of defined
268   *          properties.
269   * @param messageType
270   *          The type of message; never {@code null}.
271   *          The set of type values corresponds with the Trace Log Publisher
272   *          -message-type property values, for example 'REQUEST' for category
273   *          'HTTP'.
274   * @param message
275   *          The message to be logged; never {@code null}.
276   * @param keyValues
277   *          Keys and values that are to be logged with key=value. May be
278   *          empty, but never {@code null}.
279   *
280   */
281  public abstract void log(final HttpServletRequest request,
282                           final String messageCategory,
283                           final String messageType,
284                           final String message,
285                           final Map<String, String> keyValues);
286
287
288
289  /**
290   * {@inheritDoc}
291   */
292  public Map<List<String>,String> getExamplesArgumentSets()
293  {
294    return Collections.emptyMap();
295  }
296}