/* * 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); }