mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

boli
08.38.2007 04dfafe19f0d3687d0f0b3e51d2d5bf3d19b58bf
Enable AspectJ weaving for the new debug logging framework:
- This commit does not allow for configuring the debug logger over protocol. It can only be configured on server startup using properties.
- The settings specified during startup will remain in effect for the duration of the server.
- All messages are printed to standard out.
- Weaving could be turned off with the -DDEBUG_BUILD=false property when building the server.
- By default, the debug logger is off on server startup. It could be enabled by using the -Dorg.opends.server.debug.enabled=true.
- Debug targets may be defined with the -Dorg.opends.server.debug.target property. The syntax of this property can be found on the opends.dev.java.net documentation section.
- Debug logging is turned on by default on unit tests and printed on test failure.
- Default debug target for unit tests could be changed by using the -Dorg.opends.test.debug.target property.

Fix for issue 836
2 files deleted
4 files added
1 files renamed
20 files modified
2256 ■■■■ changed files
opends/build.xml 62 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/DirectoryThread.java 21 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/api/LogPublisher.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/task/TaskThread.java 15 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java 10 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/LogCategory.java 46 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/LogLevel.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/Logger.java 139 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/LoggerConfiguration.java 274 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/LoggerErrorHandler.java 4 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/TextLogPublisher.java 3 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/DebugConfiguration.java 274 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/DebugErrorHandler.java 65 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java 40 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java 26 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/DebugLogger.java 74 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/DebugMessageFormatter.java 273 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/TraceConfiguration.java 165 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/TraceSettings.java 145 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/loggers/debug/Tracer.java 390 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/DebugLogCategory.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/FilePermission.java 45 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/util/ServerConstants.java 18 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java 16 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java 27 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/TestLogPublisher.java 99 ●●●●● patch | view | raw | blame | history
opends/build.xml
@@ -100,6 +100,10 @@
  <!-- Properties for the EMMA code coverage tool.                 -->
  <property name="emma.dir" location="${ext.dir}/emma/lib"          />
  <!-- Properties for the AspectJ tools                            -->
  <property name="aj.dir" location="${ext.dir}/aspectj"             />
  <property name="aj.lib.dir" location="${aj.dir}/lib"              />
  <!-- Properties for the TestNG unit testing  tool.               -->
  <property name="testng.dir" location="${ext.dir}/testng"          />
  <property name="testng.lib.dir" location="${testng.dir}/lib"      />
@@ -183,12 +187,16 @@
      <format property="timestamp" pattern="yyyyMMddHHmmss" />
    </tstamp>
    <condition property="DEBUG_BUILD" value="false">
    <condition property="DEBUG_BUILD" value="true">
      <not>
        <isset property="DEBUG_BUILD" />
      </not>
    </condition>
    <condition property="weave.enabled" value="true">
      <equals arg1="${DEBUG_BUILD}" arg2="true" />
    </condition>
    <condition property="MEM" value="128M">
      <not>
        <isset property="MEM" />
@@ -367,7 +375,7 @@
  <!-- Compile the Directory Server source files. -->
  <target name="cleancompile"
       depends="cleaninit,compile,compilequicksetup,compilestatuspanel"
       depends="cleaninit,weave,compilequicksetup,compilestatuspanel"
       description="Recompile the Directory Server source files.">
  </target>
@@ -380,7 +388,7 @@
    <javac srcdir="${src.dir}" destdir="${classes.dir}" optimize="true"
         excludes="**/package-info.java"
         debug="on" debuglevel="lines,source" source="1.5" target="1.5"
         debug="on" debuglevel="lines,vars,source" source="1.5" target="1.5"
         deprecation="true" fork="true" memoryInitialSize="${MEM}"
         memoryMaximumSize="${MEM}">
      <compilerarg value="-Xlint:all" />
@@ -393,8 +401,27 @@
    </javac>
  </target>
  <target name="weave" if="weave.enabled" depends="compile">
    <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
      <classpath>
        <pathelement location="${aj.lib.dir}/aspectjtools.jar" />
      </classpath>
    </taskdef>
    <iajc inpath="${classes.dir}" destdir="${classes.dir}"
          debug="true" debuglevel="lines,source" source="1.5" target="1.5"
          deprecation="true" fork="true" maxmem="${MEM}">
      <classpath>
        <fileset dir="${lib.dir}">
          <include name="*.jar" />
        </fileset>
      </classpath>
    </iajc>
  </target>
  <!-- Compile the Quick Setup source files. -->
  <target name="compilequicksetup" depends="buildtools,compile"
  <target name="compilequicksetup" depends="buildtools,weave"
          description="Compile the Quick Setup source files.">
    <mkdir dir="${quicksetup.classes.dir}" />
@@ -780,7 +807,7 @@
  <!-- Prepare to execute the Directory Server TestNG unit tests. -->
  <target name="testinit" depends="buildtools,compile"
  <target name="testinit" depends="buildtools,weave"
         description="Prepare to execute the Directory Server TestNG unit tests.">
    <!-- If we are to perform coverage tests, then set that up. -->
@@ -994,6 +1021,19 @@
    <echo message="  -Dtest.failed=true"/>
    <echo message="      runs only the tests that failed last time"/>
    <echo message=""/>
    <echo message="  -DDEBUG_BUILD=false" />
    <echo message="      builds the server without the debug logging facility." />
    <echo message="      No debug logging messages will be included on test failures." />
    <echo message=""/>
    <echo message="  -Dtest.debug.target=org.opends.server.core:level=verbose,category=data_access"/>
    <echo message="      for example only include debug messages in the core"/>
    <echo message="      package that are related to data access and at the" />
    <echo message="      verbose level or higher. The syntax of this target" />
    <echo message="      definition is the same as the org.opends.server.debug.target.x" />
    <echo message="      property when starting OpenDS. " />
    <echo message="      Default debug target:"/>
    <echo message="      org.opends.server:level=verbose,category=caught|data|database_access|message|protocol" />
    <echo message=""/>
    <echo message="  -Dtest.packages=org.opends.server.api"/>
    <echo message="      for example runs only the tests in the api package"/>
    <echo message="      For multiple packages, separate them with a ',' and "/>
@@ -1047,7 +1087,16 @@
      </not>
    </condition>
    <!-- Cleanout the old reports.  Otherwise, the old testng-failed.xml
    <!-- This sets org.opends.test.debug.target if and only if its's not
         alreadly set. -->
    <condition property="org.opends.test.debug.target"
               value="org.opends.server:level=verbose,category=caught|data|database_access|message|protocol">
      <not>
        <isset property="org.opends.test.debug.target" />
      </not>
    </condition>
    <!-- Cleanout the old reports.  Otherwise, the old testng-failed.xml
         will hang around even if all of the tests pass. -->
    <delete>
      <fileset dir="${unittest.report.dir}" includes="*"/>
@@ -1084,6 +1133,7 @@
      <jvmarg value="-Demma.coverage.out.merge=false" />
      <jvmarg value="-Dorg.opends.server.BuildRoot=${basedir}" />
      <jvmarg value="-Dorg.opends.test.suppressOutput=${org.opends.test.suppressOutput}" />
      <jvmarg value="-Dorg.opends.test.debug.target=${org.opends.test.debug.target}" />
      <jvmarg value="-Xms${MEM}" />
      <jvmarg value="-Xmx${MEM}" />
      <xmlfileset dir="${unittest.resource.dir}" includes="testng.xml" />
opends/src/server/org/opends/server/api/DirectoryThread.java
@@ -34,6 +34,8 @@
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import java.util.Map;
import java.util.LinkedHashMap;
/**
@@ -211,5 +213,24 @@
  {
    this.task = task;
  }
  /**
   * Retrieves any relevent debug information with which this tread is
   * associated so they can be included in debug messages.
   *
   * @return debug information about this thread as a string.
   */
  public Map<String, String> getDebugProperties()
  {
    LinkedHashMap<String, String> properties =
        new LinkedHashMap<String, String>();
    properties.put("parentThread", parentThread.getName() +
        "(" + parentThread.getId() + ")");
    properties.put("isDaemon", String.valueOf(this.isDaemon()));
    return properties;
  }
}
opends/src/server/org/opends/server/api/LogPublisher.java
@@ -27,7 +27,7 @@
package org.opends.server.api;
import org.opends.server.loggers.LogRecord;
import org.opends.server.loggers.LogErrorHandler;
import org.opends.server.loggers.LoggerErrorHandler;
/**
 * LogPublishers are reponsible for distributing logged messages from
@@ -45,7 +45,7 @@
   * @param record the log record to publish.
   * @param handler the error handler to use when an error occurs.
   */
  public void publish(LogRecord record, LogErrorHandler handler);
  public void publish(LogRecord record, LoggerErrorHandler handler);
  /**
   * Releases any resources and prepare for close.
opends/src/server/org/opends/server/backends/task/TaskThread.java
@@ -38,6 +38,7 @@
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.StaticUtils.*;
import java.util.Map;
/**
@@ -223,5 +224,19 @@
      taskScheduler.threadDone(this, task);
    }
  }
  /**
   * Retrieves any relevent debug information with which this tread is
   * associated so they can be included in debug messages.
   *
   * @return debug information about this thread as a string.
   */
  public Map<String, String> getDebugProperties()
  {
    Map<String, String> properties = super.getDebugProperties();
    properties.put("task", task.toString());
    return properties;
  }
}
opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java
@@ -47,6 +47,7 @@
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.StaticUtils.*;
import java.util.Map;
/**
@@ -310,5 +311,21 @@
      }
    }
  }
  /**
   * Retrieves any relevent debug information with which this tread is
   * associated so they can be included in debug messages.
   *
   * @return debug information about this thread as a string.
   */
  public Map<String, String> getDebugProperties()
  {
    Map<String, String> properties = super.getDebugProperties();
    properties.put("clientConnection",
                   operation.getClientConnection().toString());
    properties.put("operation", operation.toString());
    return properties;
  }
}
opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java
@@ -61,9 +61,9 @@
  private static class PublishRequest
  {
    public final LogRecord record;
    public final LogErrorHandler handler;
    public final LoggerErrorHandler handler;
    PublishRequest(LogRecord record, LogErrorHandler handler)
    PublishRequest(LogRecord record, LoggerErrorHandler handler)
    {
      this.record = record;
      this.handler = handler;
@@ -129,7 +129,7 @@
        catch (Throwable t) {
          // Forward exception to error handler
          if (request != null  && request.handler != null) {
            LogErrorHandler handler= request.handler;
            LoggerErrorHandler handler= request.handler;
            handler.handleError(request.record, t);
          }
        }
@@ -141,7 +141,7 @@
  // want shutdown to start after we check for it, but before we queue
  // request.
  private synchronized void publishAsynchronously(LogRecord record,
                                                  LogErrorHandler handler)
                                                  LoggerErrorHandler handler)
  {
    // If shutting down reject, otherwise publish (if we have a publisher!)
    if (isShuttingDown()) {
@@ -167,7 +167,7 @@
   * @param record the log record to publish.
   * @param handler the error handler to use if an error occurs.
   */
  public void publish(LogRecord record, LogErrorHandler handler)
  public void publish(LogRecord record, LoggerErrorHandler handler)
  {
    // No publisher?  Off to the bit bucket.
    if (publisher != null) {
opends/src/server/org/opends/server/loggers/LogCategory.java
@@ -26,12 +26,17 @@
 */
package org.opends.server.loggers;
import java.util.ArrayList;
/**
 * The category class defines a set of standard logging types that
 * can be used to control logging output.
 */
public abstract class LogCategory
public class LogCategory
{
  private static ArrayList<LogCategory> known =  new ArrayList<LogCategory>();
  /**
   * The non-localized name of the type.
   */
@@ -42,13 +47,15 @@
   * <p>
   * Note that this constructor is "protected" to allow subclassing.
   *
   * @param name  the name of the Level, for example "SEVERE".
   * @param name  the name of the category, for example "MESSAGE".
   */
  protected LogCategory(String name) {
    if (name == null) {
      throw new NullPointerException();
    }
    this.name = name;
    known.add(this);
  }
  /**
@@ -63,9 +70,42 @@
  /**
   * Retrieves the string reprentation of this log category.
   *
   * @return the non-localized name of the Level, for example "INFO".
   * @return the non-localized name of the LogCategory, for example "ENTRY".
   */
  public final String toString() {
    return name;
  }
  /**
   * Parse a category name string into a LogCategory.
   * <p>
   * For example:
   * <ul>
   * <li> "EXIT"
   * <li> "caught"
   * </ul>
   * @param  name   string to be parsed
   * @throws IllegalArgumentException if the value is not valid.
   * Known names are the categories defined by this class or created
   * by this class with appropriate package access, or new levels defined
   * or created by subclasses.
   *
   * @return The parsed category
   */
  public static synchronized LogCategory parse(String name)
      throws IllegalArgumentException {
    // Check that name is not null.
    name.length();
    // Look for a known Level with the given  name.
    for (int i = 0; i < known.size(); i++) {
      LogCategory c = known.get(i);
      if (name.equalsIgnoreCase(c.name)) {
        return c;
      }
    }
    // OK, we've tried everything and failed
    throw new IllegalArgumentException("Bad category \"" + name + "\"");
  }
}
opends/src/server/org/opends/server/loggers/LogLevel.java
@@ -119,7 +119,7 @@
  }
  /**
   * Parse a level name string into a Level.
   * Parse a level name string into a LogLevel.
   * <p>
   * The argument string may consist of either a level name
   * or an integer value.
opends/src/server/org/opends/server/loggers/Logger.java
@@ -28,8 +28,7 @@
import org.opends.server.api.LogPublisher;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;
import java.util.List;
/**
 *  A Logger is the entry point into a message distribution
@@ -37,37 +36,36 @@
 * filters out undesired messages using a RecordFilter, and
 * sends them to a LogPublisher for further distribution.
 * Any logging exceptions encountered will be sent to a
 * LoggingErrorHandler.
 * LoggerErrorHandler.
 */
public abstract class Logger
{
 /**
   * Whether the debug logger is enabled or disabled.
   */
  protected boolean enabled;
  /**
   * The logging error handler.
   */
  protected LogErrorHandler handler;
  protected LoggerErrorHandler handler;
  /**
   * The set of publishers.
   */
  protected CopyOnWriteArrayList<LogPublisher> publishers;
  /**
   * A mutex that will be used to provide threadsafe access to methods
   * changing the set of defined publishers.
   */
  protected ReentrantLock publisherMutex;
  protected List<LogPublisher> publishers;
  /**
   * Construct a new logger object.
   *
   * @param handler the error handler to use when an error occurs.
   * @param config the logger configuration to use when construting the new
   *               logger object.
   */
  protected Logger(LogErrorHandler handler)
  protected Logger(LoggerConfiguration config)
  {
    this.publishers = new CopyOnWriteArrayList<LogPublisher>();
    this.publisherMutex = new ReentrantLock();
    this.handler = handler;
    this.enabled = config.getEnabled();
    this.publishers = config.getPublishers();
    this.handler = config.getErrorHandler();
  }
  /**
@@ -75,7 +73,7 @@
   *
   * @param record The log record to publish.
   */
  protected void publishRecord(LogRecord record)
  public void publishRecord(LogRecord record)
  {
    for(LogPublisher p : publishers)
    {
@@ -84,97 +82,36 @@
  }
  /**
   * Adds a new publisher to which log records should be sent.
   * Update this logger with the provided configuration.
   *
   * @param publisher The publisher to which records should be sent.
   * @param config the new configuration to use for this logger.
   */
  protected void addPublisher(LogPublisher publisher)
  protected void updateConfiguration(LoggerConfiguration config)
  {
    publisherMutex.lock();
    try
    boolean newEnabled = config.getEnabled();
    if(enabled && !newEnabled)
    {
      for (LogPublisher p : publishers)
      //it is now disabled. Close all publishers if any.
      for(LogPublisher publisher : publishers)
      {
        if (p.equals(publisher))
        publisher.shutdown();
        publishers.remove(publisher);
      }
    }
    if(newEnabled)
    {
      List<LogPublisher> newPublishers = config.getPublishers();
      for(LogPublisher oldPublisher : publishers)
      {
        if(!newPublishers.contains(oldPublisher))
        {
          return;
          //A publisher was removed. Make sure to close it before removing it.
          oldPublisher.shutdown();
        }
      }
      publishers.add(publisher);
    }
    catch (Exception e)
    {
      // This should never happen.
      e.printStackTrace();
    }
    finally
    {
      publisherMutex.unlock();
    }
  }
  /**
   * Removes the provided publisher so records will no longer be sent to it.
   *
   * @param publisher The publisher to remove.
   */
  protected void removePublisher(LogPublisher publisher)
  {
      publisherMutex.lock();
    try
    {
      publishers.remove(publisher);
    }
    catch (Exception e)
    {
      // This should never happen.
      e.printStackTrace();
    }
    finally
    {
      publisherMutex.unlock();
    }
  }
  /**
   * Removes all publishers so records are not sent anywhere.
   *
   * @param closePublishers whether to close the publishers when removing them.
   */
  protected void removeAllPublishers(boolean closePublishers)
  {
    publisherMutex.lock();
    try
    {
      if(closePublishers)
      {
        LogPublisher[] pubs = new LogPublisher[publishers.size()];
        publishers.toArray(pubs);
        publishers.clear();
        for(LogPublisher pub : pubs)
        {
          pub.shutdown();
        }
      }
          else
    {
      publishers.clear();
    }
    }
    catch(Exception e)
    {
      // This should never happen.
      e.printStackTrace();
    }
    finally
    {
      publisherMutex.unlock();
      this.publishers = config.getPublishers();
      this.handler = config.getErrorHandler();
    }
  }
}
opends/src/server/org/opends/server/loggers/LoggerConfiguration.java
New file
@@ -0,0 +1,274 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.loggers;
import org.opends.server.api.LogPublisher;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;
/**
 * A LoggerConfiguration encapsulates the information defining an
 * abstract log messaging system.  A LoggerConfiguration maintains at
 * least three things:
 * <ul>
 * <li>a destination to send log messages to (a LogPublisher).</li>
 * <li>an optional filter used to restrict the log messages sent
 * (a RecordFilter).</li>
 * <li>an error handler to be notified in the case of any logging
 * exceptions (a LoggerErrorHandler).</li>
 * </ul>
 *
 * A Logger will use this information to initialize the log messaging
 * system.  Additionally, a Logger will register with the LoggerConfiguration
 * object it used to allow the LoggerConfiguration to provide a single
 * point of configuration management.  On configuration changes, registered
 * Loggers will be notified.
 *
 */
public class LoggerConfiguration {
  /**
   * Whether the debug logger is enabled or disabled.
   */
  protected boolean enabled;
  /** The log destination for this configuration. */
  protected CopyOnWriteArrayList<LogPublisher> publishers;
  /**
   * A mutex that will be used to provide threadsafe access to methods
   * changing the set of defined publishers.
   */
  protected ReentrantLock publisherMutex;
  /**
   * The logging error handler.
   */
  protected LoggerErrorHandler handler;
  /** The record filter for this configuration. */
  //protected RecordFilter _filter;
  /** The loggers that need notification of configuration changes. */
  protected Set<Logger> loggers;
  /**
   * Creates a LoggerConfiguration describing an disabled logging system.
   *
   * @param handler the error handler to use for the logger configured by this
   *                configuration.
   */
  public LoggerConfiguration(LoggerErrorHandler handler)
  {
    this.enabled = false;
    this.publishers = new CopyOnWriteArrayList<LogPublisher>();
    this.publisherMutex = new ReentrantLock();
    this.handler = handler;
    this.loggers = new HashSet<Logger>();
  }
  /**
   * Enable or disable the debug logger.
   *
   * @param enable if the debug logger should be enabled.
   */
  public void setEnabled(boolean enable)
  {
    this.enabled = enable;
  }
  /**
   * Obtain the status of this logger singleton.
   *
   * @return the status of this logger.
   */
  public boolean getEnabled()
  {
    return enabled;
  }
  /**
   * Adds a new publisher to which log records should be sent.
   *
   * @param publisher The publisher to which records should be sent.
   */
  public void addPublisher(LogPublisher publisher)
  {
    publisherMutex.lock();
    try
    {
      for (LogPublisher p : publishers)
      {
        if (p.equals(publisher))
        {
          return;
        }
      }
      publishers.add(publisher);
    }
    catch (Exception e)
    {
      // This should never happen.
      e.printStackTrace();
    }
    finally
    {
      publisherMutex.unlock();
    }
  }
  /**
   * Removes the provided publisher so records will no longer be sent to it.
   *
   * @param publisher The publisher to remove.
   */
  public void removePublisher(LogPublisher publisher)
  {
    publisherMutex.lock();
    try
    {
      publishers.remove(publisher);
    }
    catch (Exception e)
    {
      // This should never happen.
      e.printStackTrace();
    }
    finally
    {
      publisherMutex.unlock();
    }
  }
  /**
   * Removes all publishers so records are not sent anywhere.
   *
   * @param closePublishers whether to close the publishers when removing them.
   */
  public void removeAllPublishers(boolean closePublishers)
  {
    publisherMutex.lock();
    try
    {
      if(closePublishers)
      {
        LogPublisher[] pubs = new LogPublisher[publishers.size()];
        publishers.toArray(pubs);
        publishers.clear();
        for(LogPublisher pub : pubs)
        {
          pub.shutdown();
        }
      }
      else
      {
        publishers.clear();
      }
    }
    catch(Exception e)
    {
      // This should never happen.
      e.printStackTrace();
    }
    finally
    {
      publisherMutex.unlock();
    }
  }
  /**
   * Retrieves the set of publishers included in this configuration.
   *
   * @return the set of publishers included in this configuration.
   */
  public List<LogPublisher> getPublishers()
  {
    return Collections.unmodifiableList(publishers);
  }
  /**
   * Retrieves the error handler included in this configuration.
   *
   * @return the error handler used by this configuration.
   */
  public LoggerErrorHandler getErrorHandler()
  {
    return handler;
  }
  /**
   * Set an error handler for this configuration.
   *
   * @param handler the error handler to set for this configuration.
   */
  public void setErrorHandler(LoggerErrorHandler handler)
  {
    this.handler= handler;
    notifyLoggers();
  }
  /**
   * Request that a logger be notified of configuration changes.
   *
   * @param logger - The Logger interested in configuration change
   * notifications.
   */
  public synchronized void registerLogger(Logger logger)
  {
    loggers.add(logger);
  }
  /**
   * Request that a logger no longer be notifed of configuration changes.
   *
   * @param logger - The Logger no longer interested in configuration change
   * notifications.
   */
  public synchronized void deregisterLogger(Logger logger)
  {
    loggers.remove(logger);
  }
  /**
   * Notify all registered loggers that the configuration has changed.
   */
  protected synchronized void notifyLoggers()
  {
    for(Logger logger : loggers)
    {
      logger.updateConfiguration(this);
    }
  }
}
opends/src/server/org/opends/server/loggers/LoggerErrorHandler.java
File was renamed from opends/src/server/org/opends/server/loggers/LogErrorHandler.java
@@ -27,13 +27,13 @@
package org.opends.server.loggers;
/**
 * A LoggingErrorHandler is used for notification of exceptions which
 * A LoggerErrorHandler is used for notification of exceptions which
 * occur during the publishing of a record.
 *
 * The advantage of using a handler is that we can handle exceptions
 * asynchronously (useful when dealing with an AsynchronousPublisher).
 */
public interface LogErrorHandler
public interface LoggerErrorHandler
{
  /**
   * Handle an exception which occurred during the publishing
opends/src/server/org/opends/server/loggers/TextLogPublisher.java
@@ -56,7 +56,8 @@
   * @param record the log record to publish.
   * @param handler the error handler to use if an error occurs.
   */
  public void publish(LogRecord record, LogErrorHandler handler)
  public synchronized void publish(LogRecord record,
                                   LoggerErrorHandler handler)
  {
    try
    {
opends/src/server/org/opends/server/loggers/debug/DebugConfiguration.java
New file
@@ -0,0 +1,274 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.loggers.debug;
import org.opends.server.loggers.*;
import org.opends.server.util.DynamicConstants;
import org.opends.server.types.DebugLogLevel;
import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_ENABLED;
import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_TARGET;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
/**
 * A LoggingConfiguration for the debug logging system.
 */
public class DebugConfiguration extends LoggerConfiguration
{
  private static final String GLOBAL= "_global";
  private Map<String, TraceSettings> classTraceSettings;
  private Map<String, Map<String, TraceSettings>> methodTraceSettings;
  /**
   * Error handler for tracing.  Tracing will be disabled
   * if too many errors occur.
   */
  private class DebugErrorHandler implements LoggerErrorHandler
  {
    private static final int ERROR_THRESHOLD= 10;
    private int _loggingErrors= 0;
    /**
     * Error handler for tracing.  Tracing will be disabled
     * if too many errors occur.
     *
     * @param record the log record that caused the error to occur.
     * @param ex the exception thrown.
     */
    public synchronized void handleError(LogRecord record, Throwable ex)
    {
      _loggingErrors++;
      DebugLogFormatter formatter = new DebugLogFormatter();
      System.err.println("Error publishing record: " +
          formatter.format(record) + ex);
      // If we've had too many write errors, just turn off
      // tracing to prevent an overflow of messages.
      if (_loggingErrors >= ERROR_THRESHOLD) {
        System.err.println("TOO MANY ERRORS FROM DEBUG LOGGER. SHUTTING DOWN");
        enabled = false;
      }
    }
  }
  /**
   * Construct a default configuration where the logger is disabled and the
   * global scope will only log at the ERROR level.
   */
  public DebugConfiguration()
  {
    super(null);
    this.setErrorHandler(new DebugErrorHandler());
    classTraceSettings = null;
    methodTraceSettings = null;
    //Set the global settings so that only errors are logged.
    addTraceSettings(null, new TraceSettings(DebugLogLevel.ERROR));
  }
  /**
   * Gets the method trace levels for a specified class.
   * @param className - a fully qualified class name to get method trace
   * levels for
   * @return an unmodifiable map of trace levels keyed by method name.  If
   * no method level tracing is configured for the scope, <b>null</b> is
   * returned.
   */
  public Map<String, TraceSettings> getMethodSettings(String className)
  {
    Map<String, TraceSettings> levels = null;
    if (enabled && methodTraceSettings != null) {
      // Method levels are always at leaves in the
      // hierarchy, so don't bother searching up.
      Map<String, TraceSettings> value= methodTraceSettings.get(className);
      if (value != null ) {
        levels= value;
      }
    }
    return levels != null ? Collections.unmodifiableMap(levels) : null;
  }
  /**
   * Get the trace settings for a specified class.
   * @param className - a fully qualified class name to get the
   * trace level for
   * @return the current trace settings for the class.
   */
  public TraceSettings getTraceSettings(String className)
  {
    TraceSettings settings = TraceSettings.DISABLED;
    // If we're not enabled, trace level is DISABLED.
    if (enabled  && classTraceSettings != null) {
      // Find most specific trace setting which covers this
      // fully qualified class name
      // Search up the hierarchy for a match.
      String searchName= className;
      Object value= null;
      value= classTraceSettings.get(searchName);
      while (value == null && searchName != null) {
        int clipPoint= searchName.lastIndexOf('$');
        if (clipPoint == -1) clipPoint= searchName.lastIndexOf('.');
        if (clipPoint != -1) {
          searchName= searchName.substring(0, clipPoint);
          value= classTraceSettings.get(searchName);
        }
        else {
          searchName= null;
        }
      }
      // Use global settings, if nothing more specific was found.
      if (value == null) value= classTraceSettings.get(GLOBAL);
      if (value != null) {
        settings= (TraceSettings)value;
      }
    }
    return 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 to set trace settings for; this is a fully
   * qualified class name or null to set the trace settings for the global
   * scope.
   * @param settings - the trace settings for the scope
   */
  public 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);
      }
    }
  }
  private synchronized void setClassSettings(String className,
                                             TraceSettings settings)
  {
    if(classTraceSettings == null) classTraceSettings =
        new HashMap<String, TraceSettings>();
    classTraceSettings.put(className, settings);
  }
  private synchronized void setMethodSettings(String className,
                                              String methodName,
                                              TraceSettings settings)
  {
    if (methodTraceSettings == null) methodTraceSettings =
        new HashMap<String, Map<String, TraceSettings>>();
    Map<String, TraceSettings> methodLevels=
        methodTraceSettings.get(className);
    if (methodLevels == null) {
      methodLevels= new TreeMap<String, TraceSettings>();
      methodTraceSettings.put(className, methodLevels);
    }
    methodLevels.put(methodName, settings);
  }
  /**
   * Retrieve the initial configuration to use on debug logger startup. Settings
   * are read from system properties.
   * If this is not a debug build of OpenDS, the resulting configuration is
   * always disabled.
   *
   * @return the initial configuration to use for the debug logger.
   */
  public static DebugConfiguration getStartupConfiguration()
  {
    String enabledProp = System.getProperty(PROPERTY_DEBUG_ENABLED);
    if(DynamicConstants.DEBUG_BUILD && (enabledProp != null &&
        (enabledProp.startsWith("T") || enabledProp.startsWith("t") ||
            enabledProp.startsWith("Y") || enabledProp.startsWith("y"))))
    {
      DebugConfiguration config = new DebugConfiguration();
      config.setEnabled(true);
      TextLogPublisher consolePublisher =
          new TextLogPublisher(TextWriter.STDOUT, new DebugLogFormatter());
      config.addPublisher(consolePublisher);
      Set<Map.Entry<Object, Object>> propertyEntries =
          System.getProperties().entrySet();
      for(Map.Entry<Object, Object> entry : propertyEntries)
      {
        if(((String)entry.getKey()).startsWith(PROPERTY_DEBUG_TARGET))
        {
          String value = (String)entry.getValue();
          int settingsStart= value.indexOf(":");
          //See if the scope and settings exists
          if(settingsStart > 0)
          {
            String scope = value.substring(0, settingsStart);
            TraceSettings settings =
                TraceSettings.parseTraceSettings(
                    value.substring(settingsStart+1));
            if(settings != null)
            {
              config.addTraceSettings(scope, settings);
            }
          }
        }
      }
      return config;
    }
    else
    {
      //If it is not enabled or not a debug build, just return the default
      //off config.
      return new DebugConfiguration();
    }
  }
}
opends/src/server/org/opends/server/loggers/debug/DebugErrorHandler.java
File was deleted
opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java
@@ -30,6 +30,7 @@
import org.opends.server.loggers.LogRecord;
import java.util.Locale;
import java.util.Map;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
@@ -66,25 +67,44 @@
      buf.append(_timestamper.format(dlr.getTimestamp()));
      buf.append(" ");
      // Emit the debug level.
      buf.append(dlr.getLevel());
      // Emit the seq num
      buf.append(dlr.getSequenceNumber());
      buf.append(" ");
      // Emit thread info.
      buf.append(dlr.getThreadName());
      buf.append("(");
      buf.append(dlr.getThreadID());
      buf.append(") ");
      // Emit debug category.
      buf.append(dlr.getCategory());
      buf.append(" ");
      // Emit the debug level.
      buf.append(dlr.getLevel());
      buf.append(" ");
      // Emit thread info.
      buf.append("thread={");
      buf.append(dlr.getThreadName());
      buf.append("(");
      buf.append(dlr.getThreadID());
      buf.append(")} ");
      if(dlr.getThreadProperties() != null)
      {
        buf.append("threadDetail={");
        for(Map.Entry entry : dlr.getThreadProperties().entrySet())
        {
          buf.append(entry.getKey());
          buf.append("=");
          buf.append(entry.getValue());
          buf.append(" ");
        }
        buf.append("} ");
      }
      // Emit method info.
      buf.append("signature={");
      buf.append(dlr.getSignature());
      buf.append(" @ ");
      buf.append(dlr.getSourceLocation());
      buf.append(" ");
      buf.append("} ");
      // Emit message.
      buf.append(dlr.getMessage());
@@ -92,7 +112,7 @@
      // Emit Stack Trace.
      if(dlr.getStackTrace() != null)
      {
        buf.append("\nStack Trace\n");
        buf.append("\nStack Trace:\n");
        buf.append(dlr.getStackTrace());
      }
opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java
@@ -34,6 +34,7 @@
import org.opends.server.types.DebugLogCategory;
import java.util.Date;
import java.util.Map;
/**
 * A DebugLogRecord is reponsible for passing tracing log messages from the
@@ -69,6 +70,11 @@
  private long threadID;
  /**
   * Detailed debug properties for thread that issued logging call.
   */
  private Map<String, String> threadProperties;
  /**
   * Event time in milliseconds since 1970.
   */
  private Date timestamp;
@@ -387,4 +393,24 @@
  public void setSequenceNumber(long seq) {
    sequenceNumber = seq;
  }
  /**
   * Set the thread properties.
   *
   * @param threadProperties the thread properties map to set.
   */
  public void setThreadProperties(Map<String, String> threadProperties)
  {
    this.threadProperties = threadProperties;
  }
  /**
   * Retrives the thread properties.
   *
   * @return the thread properties.
   */
  public Map<String, String> getThreadProperties()
  {
    return threadProperties;
  }
}
opends/src/server/org/opends/server/loggers/debug/DebugLogger.java
@@ -27,10 +27,8 @@
package org.opends.server.loggers.debug;
import org.opends.server.api.ProtocolElement;
import org.opends.server.api.LogPublisher;
import org.opends.server.loggers.Logger;
import org.opends.server.loggers.LogLevel;
import org.opends.server.loggers.LogRecord;
import java.util.Map;
import java.util.HashMap;
@@ -55,35 +53,21 @@
 */
public class DebugLogger extends Logger
{
  /**
   * Whether the debug logger is enabled or disabled.
   */
  static boolean enabled = false;
  private static DebugLogger logger = null;
  static boolean staticEnabled = false;
  private Map<String, Tracer> classTracers;
  private TraceConfiguration config;
  private DebugLogger()
  private DebugConfiguration configuration;
  private DebugLogger(DebugConfiguration config)
  {
    super(new DebugErrorHandler());
    super(config);
    configuration = config;
    classTracers = new HashMap<String, Tracer>();
    config = new TraceConfiguration();
    staticEnabled = enabled;
  }
  /**
   * Publish a record to all the registered publishers.
   *
   * @param record The log record to publish.
   */
  protected void publishRecord(LogRecord record)
  {
    for(LogPublisher p : publishers)
    {
      p.publish(record, handler);
    }
  }
  /**
   * Obtain the trace logger singleton.
@@ -92,30 +76,26 @@
  public static synchronized DebugLogger getLogger()
  {
    if (logger == null) {
      logger= new DebugLogger();
      /**
       * The debug logger is being intialized for the first time.
       * Bootstrap the debug logger when the server first starts up so
       * all debug messages are log from the first initialization of a
       * server class.
       */
      logger= new DebugLogger(DebugConfiguration.getStartupConfiguration());
    }
    return logger;
  }
  /**
   * Enable or disable the debug logger.
   *
   * @param enable if the debug logger should be enabled.
   */
  public static void enabled(boolean enable)
  {
    enabled = enable;
  }
  /**
   * Obtain the status of this logger singleton.
   *
   * @return the status of this logger.
   */
  public static boolean debugEnabled()
  {
    return enabled;
    return staticEnabled;
  }
  /**
@@ -129,21 +109,8 @@
    Tracer traceLogger = classTracers.get(className);
    if (traceLogger == null) {
      classTracers.put(className, tracer);
      tracer.updateSettings(this.configuration);
    }
    else
    {
      //TODO: handle dup case!
    }
  }
  /**
   * Retrives the current tracing configuration of the debug logger.
   *
   * @return the current tracing configuration of the debug logger.
   */
  protected TraceConfiguration getConfiguration()
  {
    return config;
  }
  /**
@@ -152,14 +119,17 @@
   *
   * @param config the new configuration to apply.
   */
  public void updateConfiguration(TraceConfiguration config)
  public synchronized void updateConfiguration(DebugConfiguration config)
  {
    this.config = config;
    super.updateConfiguration(config);
    staticEnabled = enabled;
    for(Tracer tracer : classTracers.values())
    {
      tracer.updateSettings();
      tracer.updateSettings(config);
    }
    this.configuration = config;
  }
  /**
opends/src/server/org/opends/server/loggers/debug/DebugMessageFormatter.java
New file
@@ -0,0 +1,273 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server.loggers.debug;
import java.util.*;
/**
 * This class is responsible for formatting messages and replacing
 * format tokens with the text value of message arguments in debug logging
 * records.
 */
public class DebugMessageFormatter
{
  /**
   * Construct a new debug message formatter.
   */
  public DebugMessageFormatter() {
    //no implementation needed.
  }
  /**
   * Format the message format string with the provided arguments.
   *
   * @param msg the message format string to be formatted.
   * @param msgArgs the arguments to use when replacing tokens in the message.
   * @return the formatted message string.
   */
  public String format(String msg, Object[] msgArgs)
  {
    StringBuilder buffer= new StringBuilder();
    Object[] decoratedArgs = decorateMessageArgs(msgArgs);
    if (msg == null)
    {
      concatenateArgs(decoratedArgs, buffer);
      return buffer.toString();
    }
    try
    {
      return String.format(msg, decoratedArgs);
    }
    catch (IllegalFormatException e)
    {
      // Make a more useful message than a stack trace.
      buffer.append(msg);
      concatenateArgs(decoratedArgs, buffer);
      return buffer.toString();
    }
  }
  private void concatenateArgs(Object[] args, StringBuilder buffer)
  {
    for (int i = 0; (args != null) && (i < args.length); i++) {
      buffer.append(" ").append(args[i]);
    }
  }
  private Object[] decorateMessageArgs(Object[] undecoratedArgs)
  {
    Object[] args= null;
    if (undecoratedArgs != null) {
      args= new Object[undecoratedArgs.length];
      for (int i= 0; i < args.length; i++) {
        args[i]= decorateArg(undecoratedArgs[i]);
      }
    }
    return args;
  }
  private Object decorateArg(Object arg)
  {
    Object decoratedArg= arg;
    if (arg instanceof Map) {
      decoratedArg= decorateMapArg((Map)arg);
    }
    else if (arg instanceof List) {
      decoratedArg= decorateListArg((List)arg);
    }
    else if (arg instanceof Object[]) {
      decoratedArg= decorateArrayArg((Object[])arg);
    }
    else if (arg instanceof boolean[]) {
      decoratedArg = decorateArrayArg((boolean[])arg);
    }
    else if (arg instanceof byte[]) {
      decoratedArg = decorateArrayArg((byte[])arg);
    }
    else if (arg instanceof char[]) {
      decoratedArg = decorateArrayArg((char[])arg);
    }
    else if (arg instanceof double[]) {
      decoratedArg = decorateArrayArg((double[])arg);
    }
    else if (arg instanceof float[]) {
      decoratedArg = decorateArrayArg((float[])arg);
    }
    else if (arg instanceof int[]) {
      decoratedArg = decorateArrayArg((int[])arg);
    }
    else if (arg instanceof long[]) {
      decoratedArg = decorateArrayArg((long[])arg);
    }
    return decoratedArg;
  }
  private String decorateArrayArg(Object[] array)
  {
    return decorateListArg(Arrays.asList(array));
  }
  private String decorateArrayArg(boolean[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateArrayArg(byte[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateArrayArg(char[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateArrayArg(double[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateArrayArg(float[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateArrayArg(int[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateArrayArg(long[] array)
  {
    StringBuilder buffer= new StringBuilder();
    buffer.append("[ ");
    boolean firstElement= true;
    for (int i= 0; i < array.length; i++) {
      if (i > 0) buffer.append(", ");
      buffer.append(array[i]);
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateListArg(List list)
  {
    StringBuilder buffer= new StringBuilder();
    Iterator iter= list.iterator();
    buffer.append("[ ");
    boolean firstElement= true;
    while (iter.hasNext()) {
      Object lValue= iter.next();
      if (!firstElement) buffer.append(", ");
      buffer.append(decorateArg(lValue));
      firstElement= false;
    }
    buffer.append(" ]");
    return buffer.toString();
  }
  private String decorateMapArg(Map map)
  {
    StringBuilder buffer= new StringBuilder();
    Iterator iter= map.entrySet().iterator();
    buffer.append("{ ");
    boolean firstEntry= true;
    while (iter.hasNext()) {
      Map.Entry entry= (Map.Entry)iter.next();
      if (!firstEntry) buffer.append(", ");
      buffer.append(decorateArg(entry.getKey()));
      buffer.append("=");
      buffer.append(decorateArg(entry.getValue()));
      firstEntry= false;
    }
    buffer.append(" }");
    return buffer.toString();
  }
}
opends/src/server/org/opends/server/loggers/debug/TraceConfiguration.java
File was deleted
opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
@@ -28,10 +28,12 @@
package org.opends.server.loggers.debug;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DebugLogCategory;
import org.opends.server.loggers.LogLevel;
import org.opends.server.loggers.LogCategory;
import java.util.Set;
import java.util.HashSet;
/**
 * This class encapsulates the trace settings in effect at a given traceing
@@ -43,6 +45,13 @@
  static final TraceSettings DISABLED =
      new TraceSettings(DebugLogLevel.DISABLED);
  static final String STACK_DUMP_KEYWORD = "stack";
  static final String INCLUDE_CAUSE_KEYWORD = "cause";
  static final String SUPPRESS_ARG_KEYWORD = "noargs";
  static final String SUPPRESS_RETVAL_KEYWORD = "noretval";
  static final String INCLUDE_CATEGORY_KEYWORD = "category";
  static final String LEVEL_KEYWORD = "level";
  final LogLevel level;
  final Set<LogCategory> includeCategories;
@@ -115,4 +124,140 @@
    this.stackDepth = stackDepth;
    this.includeCause = includeCause;
  }
  /**
   * Parse trace settings from the string representation.
   *
   * @param value the trace settings string to be parsed.
   * @return the trace settings parsed from the string.
   */
  protected static TraceSettings parseTraceSettings(String value)
  {
    TraceSettings settings = null;
    if(value != null)
    {
      //Touch DebugLogLevel and DebugLogCategory so they are statically
      //initialized or parse will not see all the levels/categories.
      LogLevel level = DebugLogLevel.ERROR;
      LogCategory categoryStub = DebugLogCategory.MESSAGE;
      Set<LogCategory> includeCategories = null;
      boolean noArgs = false;
      boolean noRetVal = false;
      int stackDepth = 0;
      boolean includeCause = false;
      String[] keywords = value.split(",");
      for(String keyword : keywords)
      {
        //See if stack dump keyword is included
        if(keyword.startsWith(STACK_DUMP_KEYWORD))
        {
          //See if a stack depth is included
          if(keyword.length() == STACK_DUMP_KEYWORD.length())
          {
            stackDepth = DebugStackTraceFormatter.COMPLETE_STACK;
          }
          else
          {
            int depthStart= keyword.indexOf("=", STACK_DUMP_KEYWORD.length());
            if (depthStart == STACK_DUMP_KEYWORD.length())
            {
              try
              {
                stackDepth = Integer.valueOf(keyword.substring(depthStart+1));
              }
              catch(NumberFormatException nfe)
              {
                System.err.println("The keyword " + STACK_DUMP_KEYWORD +
                    " contains an invalid depth value. The complete stack " +
                    "will be included.");
              }
            }
          }
        }
        //See if to include cause in exception messages.
        else if(keyword.equals(INCLUDE_CAUSE_KEYWORD))
        {
          includeCause = true;
        }
        //See if to supress method arguments.
        else if(keyword.equals(SUPPRESS_ARG_KEYWORD))
        {
          noArgs = true;
        }
        //See if to supress return values.
        else if(keyword.equals(SUPPRESS_RETVAL_KEYWORD))
        {
          noRetVal = true;
        }
        else if(keyword.startsWith(INCLUDE_CATEGORY_KEYWORD))
        {
          int categoryStart =
                keyword.indexOf("=", INCLUDE_CATEGORY_KEYWORD.length());
          if(keyword.length() == INCLUDE_CATEGORY_KEYWORD.length() ||
              categoryStart != INCLUDE_CATEGORY_KEYWORD.length())
          {
            System.err.println("The keyword " + INCLUDE_CATEGORY_KEYWORD +
                " does not contain an equal sign to define the set of " +
                "categories to include. All categories will be included.");
          }
          else
          {
            String[] categories =
                keyword.substring(categoryStart+1).split("[|]");
            includeCategories = new HashSet<LogCategory>();
            for(String category : categories)
            {
              try
              {
                includeCategories.add(DebugLogCategory.parse(category));
              }
              catch(IllegalArgumentException iae)
              {
                System.err.println("The keyword " + INCLUDE_CATEGORY_KEYWORD +
                    " contains an invalid debug log category: " +
                    iae.toString() + ". It will be ignored.");
              }
            }
          }
        }
        else if(keyword.startsWith(LEVEL_KEYWORD))
        {
          int levelStart =
                keyword.indexOf("=", LEVEL_KEYWORD.length());
          if(keyword.length() == LEVEL_KEYWORD.length() ||
              levelStart != LEVEL_KEYWORD.length())
          {
            System.err.println("The keyword " + LEVEL_KEYWORD +
                " does not contain an equal sign to specify the log level. " +
                "Default level of " + level.toString() + " will be used.");
          }
          else
          {
            try
            {
              level = LogLevel.parse(keyword.substring(levelStart+1));
            }
            catch(IllegalArgumentException iae)
            {
              System.err.println("The keyword " + LEVEL_KEYWORD +
                  " contains an invalid debug log level: " +
                  iae.toString() + ". Default level of " + level.toString() +
                  " will be used.");
            }
          }
        }
      }
      settings = new TraceSettings(level, includeCategories, noArgs, noRetVal,
                                   stackDepth, includeCause);
    }
    return settings;
  }
}
opends/src/server/org/opends/server/loggers/debug/Tracer.java
@@ -39,6 +39,7 @@
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
import org.opends.server.api.ProtocolElement;
import org.opends.server.api.DirectoryThread;
import org.opends.server.loggers.*;
import org.opends.server.types.DebugLogCategory;
import org.opends.server.types.DebugLogLevel;
@@ -53,7 +54,11 @@
 * Logging is always done at a level basis, with debug log messages
 * exceeding the trace threshold being traced, others being discarded.
 */
@Aspect("pertypewithin(*)")
@Aspect("pertypewithin(!@Tracer.NoDebugTracing org.opends.server..*+ && " +
    "!org.opends.server.loggers.*+ && " +
    "!org.opends.server.loggers.debug..*+ &&" +
    "!org.opends.server.types.DebugLogLevel+ && " +
    "!org.opends.server.types.DebugLogCategory+)")
public class Tracer
{
  /**
@@ -76,7 +81,7 @@
  /**
   * Pointcut for matching all toString() methods.
   */
  @Pointcut("execution(String *..toString())")
  @Pointcut("execution(* *..toString(..))")
  private void toStringMethod()
  {
  }
@@ -91,6 +96,16 @@
  }
  /**
   * Pointcut for matching all getDebugProperties() methods.
   * TODO: Make this less general. Find out if pointcut matches
   * subclass methods.
   */
  @Pointcut("execution(* *..getDebugProperties(..))")
  private void getDebugPropertiesMethod()
  {
  }
  /**
   * Pointcut for matching debugMessage() methods.
   */
  @Pointcut("call(public static void org.opends.server." +
@@ -194,9 +209,8 @@
   * Pointcut to exclude all pointcuts which should not be adviced by the
   * debug logger.
   */
  @Pointcut("within(Tracer+) || within(org.opends.server.loggers.debug..*) " +
      "|| toStringMethod() " +
      "|| getMessageMethod() || logMethods()")
  @Pointcut("toStringMethod() || getMessageMethod() || " +
      "getDebugPropertiesMethod() || logMethods()")
  private void excluded()
  {
  }
@@ -204,16 +218,47 @@
  /**
   * Pointcut for matching the execution of all public methods.
   */
  @Pointcut("execution(!@NoDebugTracing public * *(..)) && !excluded()")
  void tracedMethod()
  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
      "Tracer.NoEntryDebugTracing) public * *(..)) && " +
      "!excluded()")
  void tracedEntryMethod()
  {
  }
  /**
   * Pointcut for matching the execution of all public methods.
   */
  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
      "Tracer.NoExitDebugTracing) public * *(..)) && " +
      "!excluded()")
  void tracedExitMethod()
  {
  }
  /**
   * Pointcut for matching the execution of all public methods.
   */
  @Pointcut("execution(@Tracer.TraceThrown public * *(..)) && " +
      "!excluded()")
  void tracedThrownMethod()
  {
  }
  /**
   * Pointcut for matching the execution of all constructors.
   */
  @Pointcut("execution(!@NoDebugTracing public new(..)) && !excluded()")
  void tracedConstructor()
  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
      "Tracer.NoEntryDebugTracing) public new(..)) && !excluded()")
  void tracedEntryConstructor()
  {
  }
  /**
   * Pointcut for matching the execution of all constructors.
   */
  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
      "Tracer.NoExitDebugTracing) public new(..)) && !excluded()")
  void tracedExitConstructor()
  {
  }
@@ -222,19 +267,12 @@
   *
   * @return if debug logging is enabled.
   */
  @Pointcut("if() && tracingScope()")
  @Pointcut("if()")
  public static boolean shouldTrace()
  {
    return DebugLogger.enabled;
    return DebugLogger.staticEnabled;
  }
  /**
   * Pointcut for matching only within the scope of the server packages.
   */
  @Pointcut("within(!@NoDebugTracing org.opends.server..*)")
  protected void tracingScope()
  {
  }
  //The default level to log constructor exectuions.
  private static final LogLevel DEFAULT_CONSTRUCTOR_LEVEL =
@@ -242,6 +280,12 @@
  //The default level to log method entry and exit pointcuts.
  private static final LogLevel DEFAULT_ENTRY_EXIT_LEVEL =
      DebugLogLevel.VERBOSE;
  //The default level to log method entry and exit pointcuts.
  private static final LogLevel DEFAULT_THROWN_LEVEL =
      DebugLogLevel.ERROR;
  private static final DebugMessageFormatter msgFormatter =
      new DebugMessageFormatter();
  // The class this tracer traces.
  private String className;
@@ -258,13 +302,12 @@
   *
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   */
  @Before("staticinitialization(*) && tracingScope()")
  @Before("staticinitialization(*)")
  public void initializeTracer(JoinPoint.StaticPart thisJoinPointStaticPart)
  {
    className = thisJoinPointStaticPart.getSignature().getDeclaringTypeName();
    logger = DebugLogger.getLogger();
    logger.registerTracer(className, this);
    updateSettings();
  }
  /**
@@ -272,7 +315,7 @@
   *
   * @param thisJoinPoint the JoinPoint reflection object.
   */
  @Before("shouldTrace() && tracedConstructor()")
  @Before("shouldTrace() && tracedEntryConstructor()")
  public void traceConstructor(JoinPoint thisJoinPoint)
  {
    LogCategory category = DebugLogCategory.CONSTRUCTOR;
@@ -294,7 +337,7 @@
   * @param thisJoinPoint the JoinPoint reflection object.
   * @param obj the object this method operations on.
   */
  @Before("shouldTrace() && tracedMethod() && nonStaticContext(obj)")
  @Before("shouldTrace() && tracedEntryMethod() && nonStaticContext(obj)")
  public void traceNonStaticMethodEntry(JoinPoint thisJoinPoint, Object obj)
  {
    LogCategory category = DebugLogCategory.ENTER;
@@ -315,7 +358,7 @@
   *
   * @param thisJoinPoint the JoinPoint reflection object.
   */
  @Before("shouldTrace() && tracedMethod() && staticContext()")
  @Before("shouldTrace() && tracedEntryMethod() && staticContext()")
  public void traceStaticMethodEntry(JoinPoint thisJoinPoint)
  {
    LogCategory category = DebugLogCategory.ENTER;
@@ -337,8 +380,8 @@
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param ret the return value of the method.
   */
  @AfterReturning(pointcut = "shouldTrace() && tracedMethod() &&" +
                             "traceConstructor()",
  @AfterReturning(pointcut = "shouldTrace() && " +
      "(tracedExitMethod() || tracedExitConstructor())",
                  returning = "ret")
  public void traceReturn(JoinPoint.StaticPart thisJoinPointStaticPart,
                          Object ret)
@@ -359,12 +402,42 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param ex the exception thrown.
   */
  @AfterThrowing(pointcut = "shouldTrace() && tracedThrownMethod()",
                 throwing = "ex")
  public void traceThrown(JoinPoint.StaticPart thisJoinPointStaticPart,
                          Throwable ex)
  {
    LogCategory category = DebugLogCategory.THROWN;
    LogLevel level = DEFAULT_THROWN_LEVEL;
    Signature signature = thisJoinPointStaticPart.getSignature();
    TraceSettings settings = getSettings(signature.getName());
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(), sl.toString(),
              null, null , new Object[]{ex}, settings);
    }
  }
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   */
  @Around("shouldTrace() && logVerboseMethod() && args(msg)")
  public void traceVerbose(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart, String msg)
                             thisEnclosingJoinPointStaticPart,
                           JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                           String msg)
  {
    LogLevel level = DebugLogLevel.VERBOSE;
    LogCategory category = DebugLogCategory.MESSAGE;
@@ -373,7 +446,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, null, settings);
    }
@@ -382,13 +455,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   * @param msgArgs arguments to place into the format string.
   */
  @Around("shouldTrace() && logVerboseMethod() && args(msg, msgArgs)")
  public void traceVerbose(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart,
                           JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                           String msg, Object[] msgArgs)
  {
    LogLevel level = DebugLogLevel.VERBOSE;
@@ -398,7 +476,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, msgArgs, settings);
    }
@@ -407,12 +485,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   */
  @Around("shouldTrace() && logInfoMethod() && args(msg)")
  public void traceInfo(JoinPoint.EnclosingStaticPart
                          thisEnclosingJoinPointStaticPart, String msg)
                          thisEnclosingJoinPointStaticPart,
                        JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                        String msg)
  {
    LogLevel level = DebugLogLevel.INFO;
    LogCategory category = DebugLogCategory.MESSAGE;
@@ -421,7 +505,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, null, settings);
    }
@@ -430,13 +514,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   * @param msgArgs arguments to place into the format string.
   */
  @Around("shouldTrace() && logInfoMethod() && args(msg, msgArgs)")
  public void traceInfo(JoinPoint.EnclosingStaticPart
                          thisEnclosingJoinPointStaticPart,
                        JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                        String msg, Object[] msgArgs)
  {
    LogLevel level = DebugLogLevel.INFO;
@@ -446,7 +535,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, msgArgs, settings);
    }
@@ -455,12 +544,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   */
  @Around("shouldTrace() && logWarningMethod() && args(msg)")
  public void traceWarning(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart, String msg)
                             thisEnclosingJoinPointStaticPart,
                           JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                           String msg)
  {
    LogLevel level = DebugLogLevel.WARNING;
@@ -470,7 +565,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, null, settings);
    }
@@ -479,13 +574,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   * @param msgArgs arguments to place into the format string.
   */
  @Around("shouldTrace() && logWarningMethod() && args(msg, msgArgs)")
  public void traceWarning(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart,
                           JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                           String msg, Object[] msgArgs)
  {
    LogLevel level = DebugLogLevel.WARNING;
@@ -495,7 +595,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, msgArgs, settings);
    }
@@ -504,12 +604,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   */
  @Around("shouldTrace() && logErrorMethod() && args(msg)")
  public void traceError(JoinPoint.EnclosingStaticPart
                           thisEnclosingJoinPointStaticPart, String msg)
                           thisEnclosingJoinPointStaticPart,
                         JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                         String msg)
  {
    LogLevel level = DebugLogLevel.ERROR;
@@ -519,7 +625,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, null, settings);
    }
@@ -528,13 +634,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param msg message to format and log.
   * @param msgArgs arguments to place into the format string.
   */
  @Around("shouldTrace() && logErrorMethod() && args(msg, msgArgs)")
  public void traceError(JoinPoint.EnclosingStaticPart
                           thisEnclosingJoinPointStaticPart,
                         JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                         String msg, Object[] msgArgs)
  {
    LogLevel level = DebugLogLevel.ERROR;
@@ -544,7 +655,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(),
              sl.toString(), null, msg, msgArgs, settings);
    }
@@ -553,13 +664,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param msg message to format and log.
   */
  @Around("shouldTrace() && logMessageMethod() && args(level, msg)")
  public void traceMessage(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart,
                           JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                           LogLevel level, String msg)
  {
    LogCategory category = DebugLogCategory.MESSAGE;
@@ -568,7 +684,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(), sl.toString(),
              null, msg, null, settings);
    }
@@ -577,7 +693,10 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param msg message to format and log.
   * @param msgArgs arguments to place into the format string.
@@ -585,6 +704,8 @@
  @Around("shouldTrace() && logMessageMethod() && args(level, msg, msgArgs)")
  public void traceMessage(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart,
                           JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                           LogLevel level, String msg, Object... msgArgs)
  {
    LogCategory category = DebugLogCategory.MESSAGE;
@@ -593,7 +714,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(), sl.toString(),
              null, msg, msgArgs, settings);
    }
@@ -602,13 +723,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param ex the exception thrown.
   */
  @Around("shouldTrace() && logThrownMethod() && args(level, ex)")
  public void traceThrown(JoinPoint.EnclosingStaticPart
                            thisEnclosingJoinPointStaticPart,
                          JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                          LogLevel level, Throwable ex)
  {
    LogCategory category = DebugLogCategory.THROWN;
@@ -617,7 +743,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(), sl.toString(),
              null, null , new Object[]{ex}, settings);
    }
@@ -626,13 +752,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param ex the exception caught.
   */
  @Around("shouldTrace() && logCaughtMethod() && args(level, ex)")
  public void traceCaught(JoinPoint.EnclosingStaticPart
                            thisEnclosingJoinPointStaticPart,
                          JoinPoint.StaticPart
                            thisJoinPointStaticPart,
                          LogLevel level, Throwable ex)
  {
    LogCategory category = DebugLogCategory.CAUGHT;
@@ -641,7 +772,7 @@
    if (level.intValue() >=
        getEffectiveLevel(settings, category).intValue())
    {
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(), sl.toString(),
              null, null , new Object[]{ex}, settings);
    }
@@ -650,7 +781,10 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param status status of the JE operation.
   * @param database the database handle.
@@ -662,6 +796,8 @@
      "database, txn, key, data)")
  public void traceJEAccess(JoinPoint.EnclosingStaticPart
                              thisEnclosingJoinPointStaticPart,
                            JoinPoint.StaticPart
                              thisJoinPointStaticPart,
                            LogLevel level, OperationStatus status,
                            Database database, Transaction txn,
                            DatabaseEntry key, DatabaseEntry data)
@@ -704,26 +840,29 @@
        builder.append(" txnid=none");
      }
      // If the operation was successful we log the same common information
      // plus the key and data under category DATABASE_READ or DATABASE_WRITE
      if (status == OperationStatus.SUCCESS)
      builder.append(ServerConstants.EOL);
      if(key != null)
      {
        builder.append(ServerConstants.EOL);
        builder.append(" key:");
        builder.append("key:");
        builder.append(ServerConstants.EOL);
        StaticUtils.byteArrayToHexPlusAscii(builder, key.getData(), 4);
        if (data != null)
        {
          builder.append("data(len=");
          builder.append(data.getSize());
          builder.append("):");
          builder.append(ServerConstants.EOL);
          StaticUtils.byteArrayToHexPlusAscii(builder, data.getData(), 4);
        }
      }
      // If the operation was successful we log the same common information
      // plus the data
      if (status == OperationStatus.SUCCESS && data != null)
      {
        builder.append("data(len=");
        builder.append(data.getSize());
        builder.append("):");
        builder.append(ServerConstants.EOL);
        StaticUtils.byteArrayToHexPlusAscii(builder, data.getData(), 4);
      }
      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
      publish(category, level, signature.toLongString(), sl.toString(), null,
              builder.toString(), null, settings);
    }
@@ -731,13 +870,18 @@
  /**
   * AspectJ Implementation.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param data the data to dump.
   */
  @Around("shouldTrace() && logDataMethod() && args(level, data)")
  public void traceData(JoinPoint.EnclosingStaticPart
                          thisEnclosingJoinPointStaticPart,
                        JoinPoint.StaticPart
                          thisJoinPointStaticPart,
                        LogLevel level, byte[] data)
  {
    LogCategory category = DebugLogCategory.DATA;
@@ -756,7 +900,7 @@
        builder.append(ServerConstants.EOL);
        StaticUtils.byteArrayToHexPlusAscii(builder, data, 4);
        SourceLocation sl =
            thisEnclosingJoinPointStaticPart.getSourceLocation();
            thisJoinPointStaticPart.getSourceLocation();
        publish(category, level, signature.toLongString(), sl.toString(), null,
                builder.toString(), null, settings);
      }
@@ -766,13 +910,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param element the protocol element to dump.
   */
  @Around("shouldTrace() && logProtocolElementMethod() && args(level, element)")
  public void traceProtocolElement(JoinPoint.EnclosingStaticPart
                                     thisEnclosingJoinPointStaticPart,
                                   JoinPoint.StaticPart
                                     thisJoinPointStaticPart,
                                   LogLevel level, ProtocolElement element)
  {
    LogCategory category = DebugLogCategory.PROTOCOL;
@@ -787,7 +936,7 @@
        builder.append(ServerConstants.EOL);
        element.toString(builder, 4);
        SourceLocation sl =
            thisEnclosingJoinPointStaticPart.getSourceLocation();
            thisJoinPointStaticPart.getSourceLocation();
        publish(category, level, signature.toLongString(), sl.toString(), null,
                builder.toString(), null, settings);
      }
@@ -797,13 +946,18 @@
  /**
   * AspectJ Implementation.
   *
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
   *                                         of the code that contains the
   *                                         debug call.
   * @param thisJoinPointStaticPart the JoinPoint reflection object.
   * @param level the level of the log message.
   * @param buffer the data to dump.
   */
  @Around("shouldTrace() && logDataMethod() && args(level, buffer)")
  public void traceData(JoinPoint.EnclosingStaticPart
                          thisEnclosingJoinPointStaticPart,
                        JoinPoint.StaticPart
                          thisJoinPointStaticPart,
                        LogLevel level, ByteBuffer buffer)
  {
    LogCategory category = DebugLogCategory.DATA;
@@ -823,7 +977,7 @@
        builder.append(ServerConstants.EOL);
        StaticUtils.byteArrayToHexPlusAscii(builder, data, 4);
        SourceLocation sl =
            thisEnclosingJoinPointStaticPart.getSourceLocation();
            thisJoinPointStaticPart.getSourceLocation();
        publish(category, level, signature.toLongString(), sl.toString(), null,
                builder.toString(), null, settings);
      }
@@ -839,9 +993,10 @@
  {
    int stackDepth = 0;
    if(DebugLogCategory.ENTER.equals(category))
    if (DebugLogCategory.ENTER.equals(category) ||
        DebugLogCategory.CONSTRUCTOR.equals(category))
    {
      if (settings.noArgs)
      if(settings.noArgs)
      {
        msgArgs = null;
      }
@@ -849,12 +1004,11 @@
      {
        msg = buildDefaultEntryMessage(msgArgs.length);
      }
      stackDepth = settings.stackDepth;
    }
    if(DebugLogCategory.EXIT.equals(category))
    else if(DebugLogCategory.EXIT.equals(category))
    {
      if (settings.noRetVal)
      if(settings.noRetVal)
      {
        msgArgs = null;
      }
@@ -863,18 +1017,26 @@
        msg = "returned={%s}";
      }
    }
    if(DebugLogCategory.THROWN.equals(category))
    else if(DebugLogCategory.THROWN.equals(category))
    {
      if (msg == null)
      if(msg == null)
      {
        msg = "threw={%s}";
      }
      stackDepth = settings.stackDepth;
    }
    else if(DebugLogCategory.CAUGHT.equals(category))
    {
      if(msg == null)
      {
        msg = "caught={%s}";
      }
    }
    if (msg != null && msgArgs != null)
    {
      msg = String.format(msg, msgArgs);
      msg = msgFormatter.format(msg, msgArgs);
    }
@@ -883,21 +1045,25 @@
    record.setSignature(method);
    record.setSourceLocation(srcLocation);
    Thread thread = Thread.currentThread();
    if(thread instanceof DirectoryThread)
    {
      record.setThreadProperties(
          ((DirectoryThread)thread).getDebugProperties());
    }
    //Stack trace applies only to entry and thrown exception messages.
    if(DebugLogCategory.ENTER.equals(category) ||
        DebugLogCategory.THROWN.equals(category))
    {
      stackDepth = settings.stackDepth;
    }
    // Inject a stack trace if requested
    if (stackDepth > 0) {
      //Generate a dummy exception to get stack trace if necessary
      Throwable t;
      if(!DebugLogCategory.THROWN.equals(category) || msgArgs == null
          || msgArgs[0] == null)
      {
       t= new NullPointerException();
      }
      else
      {
        t = (Throwable)msgArgs[0];
      }
      Throwable t= new NullPointerException();
      String stack=
          DebugStackTraceFormatter.formatStackTrace(t,
                                   DebugStackTraceFormatter.SMART_FRAME_FILTER,
@@ -988,15 +1154,15 @@
  /**
   * Update the settings for this tracer.
   *
   * @param config the new trace configuration.
   */
  protected void updateSettings()
  protected void updateSettings(DebugConfiguration config)
  {
    synchronized (this)
    {
      this.settings =
          logger.getConfiguration().getTraceSettings(className);
      this.methodSettings =
          logger.getConfiguration().getMethodSettings(className);
      this.settings = config.getTraceSettings(className);
      this.methodSettings = config.getMethodSettings(className);
    }
  }
@@ -1027,4 +1193,28 @@
    return getEffectiveLevel(settings, category);
  }
  /**
   * Classes and methods annotated with @NoDebugTracing will not be weaved with
   * debug logging statements by AspectJ.
   */
  public @interface NoDebugTracing {}
  /**
   * Methods annotated with @NoEntryDebugTracing will not be weaved with
   * entry debug logging statements by AspectJ.
   */
  public @interface NoEntryDebugTracing {}
  /**
   * Methods annotated with @NoExitDebugTracing will not be weaved with
   * exit debug logging statements by AspectJ.
   */
  public @interface NoExitDebugTracing {}
  /**
   * Methods annotated with @TraceThrown will not be weaved by AspectJ with
   * debug logging statements when an exception is thrown from the method.
   */
  public @interface TraceThrown {}
}
opends/src/server/org/opends/server/types/DebugLogCategory.java
@@ -67,7 +67,7 @@
   * Only logger related classes may use this.
   */
  public static final LogCategory CAUGHT = new DebugLogCategory(
      DEBUG_CATEGORY_THROWN);
      DEBUG_CATEGORY_CAUGHT);
  /**
   * The log category that will be used for method entry messages.
opends/src/server/org/opends/server/types/FilePermission.java
@@ -1054,9 +1054,48 @@
   */
  public void toString(StringBuilder buffer)
  {
    buffer.append("FilePermission(");
    toUNIXMode(buffer, this);
    buffer.append(")");
    buffer.append("Owner=");
    if (isOwnerReadable())
    {
      buffer.append("r");
    }
    if (isOwnerWritable())
    {
      buffer.append("w");
    }
    if (isOwnerExecutable())
    {
      buffer.append("x");
    }
    buffer.append(", Group=");
    if (isGroupReadable())
    {
      buffer.append("r");
    }
    if (isGroupWritable())
    {
      buffer.append("w");
    }
    if (isGroupExecutable())
    {
      buffer.append("x");
    }
    buffer.append(", Other=");
    if (isOtherReadable())
    {
      buffer.append("r");
    }
    if (isOtherWritable())
    {
      buffer.append("w");
    }
    if (isOtherExecutable())
    {
      buffer.append("x");
    }
  }
}
opends/src/server/org/opends/server/util/ServerConstants.java
@@ -2250,6 +2250,24 @@
  /**
   * The name of the system property that can be used to enable or disable
   * the debug logger on startup.
   */
  public static final String PROPERTY_DEBUG_ENABLED =
      "org.opends.server.debug.enabled";
  /**
   * The name of the system property that can be used to specify a target
   * for the debug logger on startup.
   */
  public static final String PROPERTY_DEBUG_TARGET =
      "org.opends.server.debug.target";
  /**
   * The column at which to wrap long lines of output in the command-line tools.
   */
  public static final int MAX_LINE_WIDTH = 79;
opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
@@ -56,6 +56,9 @@
import org.opends.server.extensions.ConfigFileHandler;
import org.opends.server.loggers.Access;
import org.opends.server.loggers.Error;
import org.opends.server.loggers.debug.DebugLogFormatter;
import org.opends.server.loggers.debug.DebugConfiguration;
import org.opends.server.loggers.debug.DebugLogger;
import org.opends.server.plugins.InvocationCounterPlugin;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.types.DN;
@@ -147,6 +150,19 @@
      return;
    }
    String debugTarget = System.getProperty("org.opends.test.debug.target");
    if(debugTarget != null)
    {
      System.setProperty("org.opends.server.debug.target.1", debugTarget);
    }
    DebugConfiguration testDebugConfig =
        DebugConfiguration.getStartupConfiguration();
    testDebugConfig.removeAllPublishers(true);
    testDebugConfig.addPublisher(TestListener.DEBUG_LOG_PUBLISHER);
    DebugLogger debugLogger = DebugLogger.getLogger();
    debugLogger.updateConfiguration(testDebugConfig);
    InvocationCounterPlugin.resetStartupCalled();
    // Get the build root and use it to create a test package directory.
opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
@@ -36,6 +36,12 @@
import org.testng.xml.XmlSuite;
import static org.opends.server.util.ServerConstants.EOL;
import static org.opends.server.TestCaseUtils.originalSystemErr;
import org.opends.server.loggers.debug.DebugLogFormatter;
import org.opends.server.loggers.debug.DebugConfiguration;
import org.opends.server.loggers.debug.TraceSettings;
import org.opends.server.loggers.debug.DebugLogger;
import org.opends.server.loggers.LogLevel;
import org.opends.server.types.DebugLogLevel;
import java.util.List;
import java.util.LinkedHashMap;
@@ -64,6 +70,12 @@
  // fails, we can do the coverage report before failing the build.
  public static final String ANT_TESTS_FAILED_FILE_NAME = ".tests-failed-marker";
  /**
   * The Log Publisher for the Debug Logger
   */
  public static TestLogPublisher DEBUG_LOG_PUBLISHER =
      new TestLogPublisher(new DebugLogFormatter());
  private static final String DIVIDER_LINE = "-------------------------------------------------------------------------------" + EOL;
  public void onStart(ITestContext testContext) {
@@ -173,6 +185,8 @@
    TestErrorLogger.clear();
    TestCaseUtils.clearSystemOutContents();
    TestCaseUtils.clearSystemErrContents();
    DEBUG_LOG_PUBLISHER.clear();
  }
@@ -231,6 +245,19 @@
      }
    }
    messages = DEBUG_LOG_PUBLISHER.getMessages();
    if(! messages.isEmpty())
    {
      failureInfo.append(EOL);
      failureInfo.append("Debug Log Messages:");
      failureInfo.append(EOL);
      for (String message : messages)
      {
        failureInfo.append(message);
        failureInfo.append(EOL);
      }
    }
    String systemOut = TestCaseUtils.getSystemOutContents();
    if (systemOut.length() > 0) {
      failureInfo.append(EOL + "System.out contents:" + EOL + systemOut);
opends/tests/unit-tests-testng/src/server/org/opends/server/TestLogPublisher.java
New file
@@ -0,0 +1,99 @@
/*
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * 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
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  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
 *
 *
 *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
 */
package org.opends.server;
import org.opends.server.api.LogPublisher;
import org.opends.server.loggers.LoggerErrorHandler;
import org.opends.server.loggers.TextLogFormatter;
import org.opends.server.loggers.LogRecord;
import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;
/**
 * This class provides an implementation of an log publisher which will store
 * all messages logged in memory.  It provides methods to retrieve and clear the
 * sets of accumulated log messages.  It is only intended for use in the context
 * of the unit test framework, where it will provide a means of getting any
 * log messages associated with failed test cases.
 */
public class TestLogPublisher implements LogPublisher
{
  private TextLogFormatter formatter;
  // The list that will hold the messages logged.
  private final LinkedList<String> messageList;
  public TestLogPublisher(TextLogFormatter formatter)
  {
    this.messageList = new LinkedList<String>();
    this.formatter = formatter;
  }
  public synchronized void publish(LogRecord record,
                                   LoggerErrorHandler handler)
  {
    try
    {
      messageList.add(formatter.format(record));
    }
    catch(Throwable t)
    {
      if(handler != null)
      {
        handler.handleError(record, t);
      }
    }
  }
  public synchronized void shutdown()
  {
    messageList.clear();
  }
  /**
   * Retrieves a copy of the set of messages logged to this error logger since
   * the last time it was cleared.  A copy of the list is returned to avoid
   * a ConcurrentModificationException.
   *
   * @return  The set of messages logged to this error logger since the last
   *          time it was cleared.
   */
  public synchronized List<String> getMessages()
  {
      return new ArrayList<String>(messageList);
  }
  /**
   * Clears any messages currently stored by this logger.
   */
  public synchronized void clear()
  {
    messageList.clear();
  }
}