001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2009 Sun Microsystems, Inc. 015 * Portions Copyright 2012-2015 ForgeRock AS. 016 */ 017package org.opends.server.loggers; 018 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.TreeMap; 023 024import org.forgerock.i18n.LocalizableMessage; 025import org.opends.server.admin.std.server.DebugLogPublisherCfg; 026 027/** 028 * This class defines the set of methods and structures that must be 029 * implemented for a Directory Server debug log publisher. 030 * 031 * @param <T> The type of debug log publisher configuration handled 032 * by this log publisher implementation. 033 */ 034@org.opends.server.types.PublicAPI( 035 stability=org.opends.server.types.StabilityLevel.VOLATILE, 036 mayInstantiate=false, 037 mayExtend=true, 038 mayInvoke=false) 039public abstract class DebugLogPublisher<T extends DebugLogPublisherCfg> 040 implements LogPublisher<T> 041{ 042 /** The default global settings key. */ 043 private static final String GLOBAL= "_global"; 044 045 /** The map of class names to their trace settings. */ 046 private Map<String,TraceSettings> classTraceSettings; 047 048 /** The map of class names to their method trace settings. */ 049 private Map<String,Map<String,TraceSettings>> methodTraceSettings; 050 051 052 053 /** 054 * Construct a default configuration where the global scope will 055 * only log at the ERROR level. 056 */ 057 protected DebugLogPublisher() 058 { 059 classTraceSettings = null; 060 methodTraceSettings = null; 061 062 //Set the global settings so that nothing is logged. 063 addTraceSettings(null, TraceSettings.DISABLED); 064 } 065 066 067 068 /** {@inheritDoc} */ 069 @Override 070 public boolean isConfigurationAcceptable(T configuration, 071 List<LocalizableMessage> unacceptableReasons) 072 { 073 // This default implementation does not perform any special 074 // validation. It should be overridden by debug log publisher 075 // implementations that wish to perform more detailed validation. 076 return true; 077 } 078 079 080 081 /** 082 * Gets the method trace levels for a specified class. 083 * 084 * @param className The fully-qualified name of the class for 085 * which to get the trace levels. 086 * 087 *@return An unmodifiable map of trace levels keyed by method name, 088 * or {@code null} if no method-level tracing is configured 089 * for the scope. 090 */ 091 final Map<String,TraceSettings> getMethodSettings( 092 String className) 093 { 094 if(methodTraceSettings == null) 095 { 096 return null; 097 } 098 else 099 { 100 return methodTraceSettings.get(className); 101 } 102 } 103 104 105 106 /** 107 * Get the trace settings for a specified class. 108 * 109 * @param className 110 * The fully-qualified name of the class for which to get the trace 111 * levels. 112 * @return The current trace settings for the class. 113 */ 114 final TraceSettings getClassSettings(String className) 115 { 116 TraceSettings settings = null; 117 if (classTraceSettings != null) 118 { 119 // Find most specific trace setting 120 // which covers this fully qualified class name 121 // Search up the hierarchy for a match. 122 String searchName = className; 123 settings = classTraceSettings.get(searchName); 124 while (settings == null && searchName != null) 125 { 126 int clipPoint = searchName.lastIndexOf('$'); 127 if (clipPoint == -1) 128 { 129 clipPoint = searchName.lastIndexOf('.'); 130 } 131 if (clipPoint != -1) 132 { 133 searchName = searchName.substring(0, clipPoint); 134 settings = classTraceSettings.get(searchName); 135 } 136 else 137 { 138 searchName = null; 139 } 140 } 141 // Try global settings 142 // only if no specific target is defined 143 if (settings == null && classTraceSettings.size()==1) { 144 settings = classTraceSettings.get(GLOBAL); 145 } 146 } 147 return settings == null ? TraceSettings.DISABLED : settings; 148 } 149 150 151 152 /** 153 * Adds a trace settings to the current set for a specified scope. 154 * If a scope is not specified, the settings will be set for the 155 * global scope. The global scope settings are used when no other 156 * scope matches. 157 * 158 * @param scope The scope for which to set the trace settings. 159 * This should be a fully-qualified class name, or 160 * {@code null} to set the trace settings for the 161 * global scope. 162 * @param settings The trace settings for the specified scope. 163 */ 164 public final void addTraceSettings(String scope, TraceSettings settings) 165 { 166 if (scope == null) { 167 setClassSettings(GLOBAL, settings); 168 } 169 else { 170 int methodPt= scope.lastIndexOf('#'); 171 if (methodPt != -1) { 172 String methodName= scope.substring(methodPt+1); 173 scope= scope.substring(0, methodPt); 174 setMethodSettings(scope, methodName, settings); 175 } 176 else { 177 setClassSettings(scope, settings); 178 } 179 } 180 } 181 182 /** 183 * Determine whether a trace setting is already defined for a particular 184 * scope. 185 * 186 * @param scope 187 * The scope for which to make the determination. This should be a 188 * fully-qualified class name. 189 * @return {@code true} if a trace settings is defined for the specified 190 * scope, {@code false} otherwise. 191 */ 192 final boolean hasTraceSettings(String scope) 193 { 194 int methodPt = scope.lastIndexOf('#'); 195 if (methodPt != -1) 196 { 197 String methodName = scope.substring(methodPt + 1); 198 scope = scope.substring(0, methodPt); 199 if (methodTraceSettings != null) 200 { 201 Map<String, TraceSettings> methodLevels = 202 methodTraceSettings.get(scope); 203 if (methodLevels != null) 204 { 205 return methodLevels.containsKey(methodName); 206 } 207 } 208 } 209 else if (classTraceSettings != null) 210 { 211 return classTraceSettings.containsKey(scope); 212 } 213 return false; 214 } 215 216 217 218 /** 219 * Remove a trace setting by scope. 220 * 221 * @param scope The scope for which to remove the trace setting. 222 * This should be a fully-qualified class name, or 223 * {@code null} to remove the trace setting for the 224 * global scope. 225 * 226 * @return The trace settings for the specified scope, or 227 * {@code null} if no trace setting is defined for that 228 * scope. 229 */ 230 final TraceSettings removeTraceSettings(String scope) 231 { 232 TraceSettings removedSettings = null; 233 if (scope == null) { 234 if(classTraceSettings != null) 235 { 236 removedSettings = classTraceSettings.remove(GLOBAL); 237 } 238 } 239 else { 240 int methodPt= scope.lastIndexOf('#'); 241 if (methodPt != -1) { 242 String methodName= scope.substring(methodPt+1); 243 scope= scope.substring(0, methodPt); 244 if(methodTraceSettings != null) 245 { 246 Map<String, TraceSettings> methodLevels = 247 methodTraceSettings.get(scope); 248 if(methodLevels != null) 249 { 250 removedSettings = methodLevels.remove(methodName); 251 if(methodLevels.isEmpty()) 252 { 253 methodTraceSettings.remove(scope); 254 } 255 } 256 } 257 } 258 else { 259 if(classTraceSettings != null) 260 { 261 removedSettings = classTraceSettings.remove(scope); 262 } 263 } 264 } 265 266 return removedSettings; 267 } 268 269 /** 270 * Set the trace settings for a class. 271 * 272 * @param className The class name. 273 * @param settings The trace settings for the class. 274 */ 275 private final synchronized void setClassSettings(String className, TraceSettings settings) 276 { 277 if (classTraceSettings == null) 278 { 279 classTraceSettings = new HashMap<>(); 280 } 281 classTraceSettings.put(className, settings); 282 } 283 284 285 286 /** 287 * Set the method settings for a particular method in a class. 288 * 289 * @param className The class name. 290 * @param methodName The method name. 291 * @param settings The trace settings for the method. 292 */ 293 private final synchronized void setMethodSettings(String className, 294 String methodName, TraceSettings settings) 295 { 296 if (methodTraceSettings == null) { 297 methodTraceSettings = new HashMap<>(); 298 } 299 Map<String, TraceSettings> methodLevels = methodTraceSettings.get(className); 300 if (methodLevels == null) 301 { 302 methodLevels = new TreeMap<>(); 303 methodTraceSettings.put(className, methodLevels); 304 } 305 methodLevels.put(methodName, settings); 306 } 307 308 309 310 /** 311 * Log an arbitrary event in a method. 312 * @param settings The current trace settings in effect. 313 * @param signature The method signature. 314 * @param sourceLocation The location of the method in the source. 315 * @param msg The message to be logged. 316 * @param stackTrace The stack trace at the time the message 317 * is logged or null if its not available. 318 */ 319 public abstract void trace(TraceSettings settings, String signature, 320 String sourceLocation, String msg, StackTraceElement[] stackTrace); 321 322 323 324 /** 325 * Log a caught exception in a method. 326 * @param settings The current trace settings in effect. 327 * @param signature The method signature. 328 * @param sourceLocation The location of the method in the source. 329 * @param msg The message to be logged. 330 * @param ex The exception that was caught. 331 * @param stackTrace The stack trace at the time the exception 332 * is caught or null if its not available. 333 */ 334 public abstract void traceException(TraceSettings settings, String signature, 335 String sourceLocation, String msg, Throwable ex, 336 StackTraceElement[] stackTrace); 337 338}