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-2016 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.forgerock.opendj.server.config.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  /** Construct a default configuration where the global scope will only log at the ERROR level. */
054  protected DebugLogPublisher()
055  {
056    classTraceSettings = null;
057    methodTraceSettings = null;
058
059    //Set the global settings so that nothing is logged.
060    addTraceSettings(null, TraceSettings.DISABLED);
061  }
062
063
064
065  @Override
066  public boolean isConfigurationAcceptable(T configuration,
067                      List<LocalizableMessage> unacceptableReasons)
068  {
069    // This default implementation does not perform any special
070    // validation. It should be overridden by debug log publisher
071    // implementations that wish to perform more detailed validation.
072    return true;
073  }
074
075
076
077  /**
078   * Gets the method trace levels for a specified class.
079   *
080   * @param  className  The fully-qualified name of the class for
081   *                    which to get the trace levels.
082   *
083   *@return  An unmodifiable map of trace levels keyed by method name,
084   *         or {@code null} if no method-level tracing is configured
085   *         for the scope.
086   */
087  final Map<String,TraceSettings> getMethodSettings(
088                                              String className)
089  {
090    if(methodTraceSettings == null)
091    {
092      return null;
093    }
094    else
095    {
096      return methodTraceSettings.get(className);
097    }
098  }
099
100
101
102  /**
103   * Get the trace settings for a specified class.
104   *
105   * @param className
106   *          The fully-qualified name of the class for which to get the trace
107   *          levels.
108   * @return The current trace settings for the class.
109   */
110  final TraceSettings getClassSettings(String className)
111  {
112    TraceSettings settings = null;
113    if (classTraceSettings != null)
114    {
115      // Find most specific trace setting
116      // which covers this fully qualified class name
117      // Search up the hierarchy for a match.
118      String searchName = className;
119      settings = classTraceSettings.get(searchName);
120      while (settings == null && searchName != null)
121      {
122        int clipPoint = searchName.lastIndexOf('$');
123        if (clipPoint == -1)
124        {
125          clipPoint = searchName.lastIndexOf('.');
126        }
127        if (clipPoint != -1)
128        {
129          searchName = searchName.substring(0, clipPoint);
130          settings = classTraceSettings.get(searchName);
131        }
132        else
133        {
134          searchName = null;
135        }
136      }
137      // Try global settings
138      // only if no specific target is defined
139      if (settings == null && classTraceSettings.size()==1) {
140        settings = classTraceSettings.get(GLOBAL);
141      }
142    }
143    return settings == null ? TraceSettings.DISABLED : settings;
144  }
145
146
147
148  /**
149   * Adds a trace settings to the current set for a specified scope.
150   * If a scope is not specified, the settings will be set for the
151   * global scope. The global scope settings are used when no other
152   * scope matches.
153   *
154   * @param  scope     The scope for which to set the trace settings.
155   *                   This should be a fully-qualified class name, or
156   *                   {@code null} to set the trace settings for the
157   *                   global scope.
158   * @param  settings  The trace settings for the specified scope.
159   */
160  public final void addTraceSettings(String scope, TraceSettings settings)
161  {
162    if (scope == null) {
163      setClassSettings(GLOBAL, settings);
164    }
165    else {
166      int methodPt= scope.lastIndexOf('#');
167      if (methodPt != -1) {
168        String methodName= scope.substring(methodPt+1);
169        scope= scope.substring(0, methodPt);
170        setMethodSettings(scope, methodName, settings);
171      }
172      else {
173        setClassSettings(scope, settings);
174      }
175    }
176  }
177
178  /**
179   * Determine whether a trace setting is already defined for a particular
180   * scope.
181   *
182   * @param scope
183   *          The scope for which to make the determination. This should be a
184   *          fully-qualified class name.
185   * @return {@code true} if a trace settings is defined for the specified
186   *         scope, {@code false} otherwise.
187   */
188  final boolean hasTraceSettings(String scope)
189  {
190    int methodPt = scope.lastIndexOf('#');
191    if (methodPt != -1)
192    {
193      String methodName = scope.substring(methodPt + 1);
194      scope = scope.substring(0, methodPt);
195      if (methodTraceSettings != null)
196      {
197        Map<String, TraceSettings> methodLevels =
198            methodTraceSettings.get(scope);
199        if (methodLevels != null)
200        {
201          return methodLevels.containsKey(methodName);
202        }
203      }
204    }
205    else if (classTraceSettings != null)
206    {
207      return classTraceSettings.containsKey(scope);
208    }
209    return false;
210  }
211
212
213
214  /**
215   * Remove a trace setting by scope.
216   *
217   * @param  scope  The scope for which to remove the trace setting.
218   *                This should be a fully-qualified class name, or
219   *                {@code null} to remove the trace setting for the
220   *                global scope.
221   *
222   * @return  The trace settings for the specified scope, or
223   *          {@code null} if no trace setting is defined for that
224   *          scope.
225   */
226  final TraceSettings removeTraceSettings(String scope)
227  {
228    TraceSettings removedSettings = null;
229    if (scope == null) {
230      if(classTraceSettings != null)
231      {
232        removedSettings =  classTraceSettings.remove(GLOBAL);
233      }
234    }
235    else {
236      int methodPt= scope.lastIndexOf('#');
237      if (methodPt != -1) {
238        String methodName= scope.substring(methodPt+1);
239        scope= scope.substring(0, methodPt);
240        if(methodTraceSettings != null)
241        {
242          Map<String, TraceSettings> methodLevels =
243              methodTraceSettings.get(scope);
244          if(methodLevels != null)
245          {
246            removedSettings = methodLevels.remove(methodName);
247            if(methodLevels.isEmpty())
248            {
249              methodTraceSettings.remove(scope);
250            }
251          }
252        }
253      }
254      else {
255        if(classTraceSettings != null)
256        {
257          removedSettings =  classTraceSettings.remove(scope);
258        }
259      }
260    }
261
262    return removedSettings;
263  }
264
265  /**
266   * Set the trace settings for a class.
267   *
268   * @param  className  The class name.
269   * @param  settings   The trace settings for the class.
270   */
271  private final synchronized void setClassSettings(String className, TraceSettings settings)
272  {
273    if (classTraceSettings == null)
274    {
275      classTraceSettings = new HashMap<>();
276    }
277    classTraceSettings.put(className, settings);
278  }
279
280
281
282  /**
283   * Set the method settings for a particular method in a class.
284   *
285   * @param  className   The class name.
286   * @param  methodName  The method name.
287   * @param  settings    The trace settings for the method.
288   */
289  private final synchronized void setMethodSettings(String className,
290      String methodName, TraceSettings settings)
291  {
292    if (methodTraceSettings == null) {
293      methodTraceSettings = new HashMap<>();
294    }
295    Map<String, TraceSettings> methodLevels = methodTraceSettings.get(className);
296    if (methodLevels == null)
297    {
298      methodLevels = new TreeMap<>();
299      methodTraceSettings.put(className, methodLevels);
300    }
301    methodLevels.put(methodName, settings);
302  }
303
304
305
306  /**
307   * Log an arbitrary event in a method.
308   * @param  settings        The current trace settings in effect.
309   * @param  signature       The method signature.
310   * @param  sourceLocation  The location of the method in the source.
311   * @param  msg             The message to be logged.
312   * @param  stackTrace      The stack trace at the time the message
313   *                         is logged or null if its not available.
314   */
315  public abstract void trace(TraceSettings settings, String signature,
316      String sourceLocation, String msg, StackTraceElement[] stackTrace);
317
318
319
320  /**
321   * Log a caught exception 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  ex              The exception that was caught.
327   * @param  stackTrace      The stack trace at the time the exception
328   *                         is caught or null if its not available.
329   */
330  public abstract void traceException(TraceSettings settings, String signature,
331      String sourceLocation, String msg, Throwable ex,
332      StackTraceElement[] stackTrace);
333
334}