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}