/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2009 Sun Microsystems, Inc.
* Portions Copyright 2012-2015 ForgeRock AS.
*/
package org.opends.server.loggers;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.server.admin.std.server.DebugLogPublisherCfg;
/**
* This class defines the set of methods and structures that must be
* implemented for a Directory Server debug log publisher.
*
* @param <T> The type of debug log publisher configuration handled
* by this log publisher implementation.
*/
@org.opends.server.types.PublicAPI(
stability=org.opends.server.types.StabilityLevel.VOLATILE,
mayInstantiate=false,
mayExtend=true,
mayInvoke=false)
public abstract class DebugLogPublisher<T extends DebugLogPublisherCfg>
implements LogPublisher<T>
{
/** The default global settings key. */
private static final String GLOBAL= "_global";
/** The map of class names to their trace settings. */
private Map<String,TraceSettings> classTraceSettings;
/** The map of class names to their method trace settings. */
private Map<String,Map<String,TraceSettings>> methodTraceSettings;
/**
* Construct a default configuration where the global scope will
* only log at the ERROR level.
*/
protected DebugLogPublisher()
{
classTraceSettings = null;
methodTraceSettings = null;
//Set the global settings so that nothing is logged.
addTraceSettings(null, TraceSettings.DISABLED);
}
/** {@inheritDoc} */
@Override
public boolean isConfigurationAcceptable(T configuration,
List<LocalizableMessage> unacceptableReasons)
{
// This default implementation does not perform any special
// validation. It should be overridden by debug log publisher
// implementations that wish to perform more detailed validation.
return true;
}
/**
* Gets the method trace levels for a specified class.
*
* @param className The fully-qualified name of the class for
* which to get the trace levels.
*
*@return An unmodifiable map of trace levels keyed by method name,
* or {@code null} if no method-level tracing is configured
* for the scope.
*/
final Map<String,TraceSettings> getMethodSettings(
String className)
{
if(methodTraceSettings == null)
{
return null;
}
else
{
return methodTraceSettings.get(className);
}
}
/**
* Get the trace settings for a specified class.
*
* @param className
* The fully-qualified name of the class for which to get the trace
* levels.
* @return The current trace settings for the class.
*/
final TraceSettings getClassSettings(String className)
{
TraceSettings settings = null;
if (classTraceSettings != null)
{
// Find most specific trace setting
// which covers this fully qualified class name
// Search up the hierarchy for a match.
String searchName = className;
settings = classTraceSettings.get(searchName);
while (settings == null && searchName != null)
{
int clipPoint = searchName.lastIndexOf('$');
if (clipPoint == -1)
{
clipPoint = searchName.lastIndexOf('.');
}
if (clipPoint != -1)
{
searchName = searchName.substring(0, clipPoint);
settings = classTraceSettings.get(searchName);
}
else
{
searchName = null;
}
}
// Try global settings
// only if no specific target is defined
if (settings == null && classTraceSettings.size()==1) {
settings = classTraceSettings.get(GLOBAL);
}
}
return settings == null ? TraceSettings.DISABLED : settings;
}
/**
* Adds a trace settings to the current set for a specified scope.
* If a scope is not specified, the settings will be set for the
* global scope. The global scope settings are used when no other
* scope matches.
*
* @param scope The scope for which to set the trace settings.
* This should be a fully-qualified class name, or
* {@code null} to set the trace settings for the
* global scope.
* @param settings The trace settings for the specified scope.
*/
public final void addTraceSettings(String scope, TraceSettings settings)
{
if (scope == null) {
setClassSettings(GLOBAL, settings);
}
else {
int methodPt= scope.lastIndexOf('#');
if (methodPt != -1) {
String methodName= scope.substring(methodPt+1);
scope= scope.substring(0, methodPt);
setMethodSettings(scope, methodName, settings);
}
else {
setClassSettings(scope, settings);
}
}
}
/**
* Determine whether a trace setting is already defined for a particular
* scope.
*
* @param scope
* The scope for which to make the determination. This should be a
* fully-qualified class name.
* @return {@code true} if a trace settings is defined for the specified
* scope, {@code false} otherwise.
*/
final boolean hasTraceSettings(String scope)
{
int methodPt = scope.lastIndexOf('#');
if (methodPt != -1)
{
String methodName = scope.substring(methodPt + 1);
scope = scope.substring(0, methodPt);
if (methodTraceSettings != null)
{
Map<String, TraceSettings> methodLevels =
methodTraceSettings.get(scope);
if (methodLevels != null)
{
return methodLevels.containsKey(methodName);
}
}
}
else if (classTraceSettings != null)
{
return classTraceSettings.containsKey(scope);
}
return false;
}
/**
* Remove a trace setting by scope.
*
* @param scope The scope for which to remove the trace setting.
* This should be a fully-qualified class name, or
* {@code null} to remove the trace setting for the
* global scope.
*
* @return The trace settings for the specified scope, or
* {@code null} if no trace setting is defined for that
* scope.
*/
final TraceSettings removeTraceSettings(String scope)
{
TraceSettings removedSettings = null;
if (scope == null) {
if(classTraceSettings != null)
{
removedSettings = classTraceSettings.remove(GLOBAL);
}
}
else {
int methodPt= scope.lastIndexOf('#');
if (methodPt != -1) {
String methodName= scope.substring(methodPt+1);
scope= scope.substring(0, methodPt);
if(methodTraceSettings != null)
{
Map<String, TraceSettings> methodLevels =
methodTraceSettings.get(scope);
if(methodLevels != null)
{
removedSettings = methodLevels.remove(methodName);
if(methodLevels.isEmpty())
{
methodTraceSettings.remove(scope);
}
}
}
}
else {
if(classTraceSettings != null)
{
removedSettings = classTraceSettings.remove(scope);
}
}
}
return removedSettings;
}
/**
* Set the trace settings for a class.
*
* @param className The class name.
* @param settings The trace settings for the class.
*/
private final synchronized void setClassSettings(String className, TraceSettings settings)
{
if (classTraceSettings == null)
{
classTraceSettings = new HashMap<>();
}
classTraceSettings.put(className, settings);
}
/**
* Set the method settings for a particular method in a class.
*
* @param className The class name.
* @param methodName The method name.
* @param settings The trace settings for the method.
*/
private final synchronized void setMethodSettings(String className,
String methodName, TraceSettings settings)
{
if (methodTraceSettings == null) {
methodTraceSettings = new HashMap<>();
}
Map<String, TraceSettings> methodLevels = methodTraceSettings.get(className);
if (methodLevels == null)
{
methodLevels = new TreeMap<>();
methodTraceSettings.put(className, methodLevels);
}
methodLevels.put(methodName, settings);
}
/**
* Log an arbitrary event in a method.
* @param settings The current trace settings in effect.
* @param signature The method signature.
* @param sourceLocation The location of the method in the source.
* @param msg The message to be logged.
* @param stackTrace The stack trace at the time the message
* is logged or null if its not available.
*/
public abstract void trace(TraceSettings settings, String signature,
String sourceLocation, String msg, StackTraceElement[] stackTrace);
/**
* Log a caught exception in a method.
* @param settings The current trace settings in effect.
* @param signature The method signature.
* @param sourceLocation The location of the method in the source.
* @param msg The message to be logged.
* @param ex The exception that was caught.
* @param stackTrace The stack trace at the time the exception
* is caught or null if its not available.
*/
public abstract void traceException(TraceSettings settings, String signature,
String sourceLocation, String msg, Throwable ex,
StackTraceElement[] stackTrace);
}