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