From f73b655466092169abac34833fb628fce1fcdebe Mon Sep 17 00:00:00 2001
From: jcduff <jcduff@localhost>
Date: Thu, 23 Oct 2008 14:04:24 +0000
Subject: [PATCH] The commit will bring the following features :     - An updated version of the underlying database. BDB JE 3.3 is now used.     - Attribute API refactoring providing a better abstraction and offering improved performances.     - A new GUI called the Control-Panel to replace the Status-Panel: the specifications for this       GUI are available on OpenDS Wiki and contains a link to a mockup.        See <https://www.opends.org/wiki/page/ControlPanelUISpecification>.     - Some changes in the replication protocol to implement "Assured Replication Mode". The        specifications are on OpenDS Wiki at <https://www.opends.org/wiki/page/AssuredMode> and section 7       described some of the replication changes required to support this. Assured Replication is not finished,       but the main replication protocol changes to support it are done. As explained by Gilles on an email on       the Dev mailing list (http://markmail.org/message/46rgo3meq3vriy4a), with these changes the newer versions       of OpenDS may not be able to replicate with OpenDS 1.0 instances.     - Support for Service Tags on the platforms where the functionality is available and enabled. Specifications       are published at <https://www.opends.org/wiki/page/OpenDSServiceTagEnabled>. For more information on       Service Tags see <http://wikis.sun.com/display/ServiceTag/Sun+Service+Tag+FAQ>.     - The Admin Connector service. In order to provide agentry of the OpenDS server at any time, a new service       has been added, dedicated to the administration, configuration and monitoring of the server.       An overview of the Admin Connector service and it's use is available on the       OpenDS wiki <https://www.opends.org/wiki/page/ManagingAdministrationTrafficToTheServer>     - Updates to the various command line tools to support the Admin Connector service.     - Some internal re-architecting of the server to put the foundation of future developments such as virtual       directory services. The new NetworkGroups and WorkFlow internal services which have been specified in       <https://www.opends.org/wiki/page/BasicOperationRoutingThroughNetworkGroup> are now implemented.     - Many bug fixes...

---
 opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java | 2299 ++++++++++++++++++++++++++--------------------------------
 1 files changed, 1,049 insertions(+), 1,250 deletions(-)

diff --git a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
index 11f4b4a..751bd5a 100644
--- a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -25,17 +25,27 @@
  *      Copyright 2006-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.loggers;
-import org.opends.messages.Message;
 
 
+
+import static org.opends.messages.ConfigMessages.*;
+import static org.opends.server.util.StaticUtils.*;
+
 import java.io.File;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
 
+import org.opends.messages.Message;
+import org.opends.messages.MessageBuilder;
 import org.opends.server.admin.server.ConfigurationChangeListener;
-import org.opends.server.admin.std.server.FileBasedAccessLogPublisherCfg;
 import org.opends.server.admin.std.server.AccessLogPublisherCfg;
-import org.opends.server.api.*;
+import org.opends.server.admin.std.server.FileBasedAccessLogPublisherCfg;
+import org.opends.server.api.AccessLogPublisher;
+import org.opends.server.api.ClientConnection;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.AbandonOperation;
 import org.opends.server.core.AddOperation;
@@ -44,48 +54,59 @@
 import org.opends.server.core.DeleteOperation;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ExtendedOperation;
-import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.core.UnbindOperation;
-import org.opends.server.types.*;
+import org.opends.server.types.AuthenticationInfo;
+import org.opends.server.types.ByteString;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.DisconnectReason;
+import org.opends.server.types.FilePermission;
+import org.opends.server.types.InitializationException;
+import org.opends.server.types.Operation;
+import org.opends.server.types.ResultCode;
 import org.opends.server.util.TimeThread;
 
-import static org.opends.messages.ConfigMessages.*;
-
-import org.opends.messages.MessageBuilder;
-import static org.opends.server.util.StaticUtils.getFileForPath;
-import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
 
 
 /**
  * This class provides the implementation of the access logger used by
  * the directory server.
  */
-public class TextAccessLogPublisher
-    extends AccessLogPublisher<FileBasedAccessLogPublisherCfg>
-    implements ConfigurationChangeListener<FileBasedAccessLogPublisherCfg>
+public class TextAccessLogPublisher extends
+    AccessLogPublisher<FileBasedAccessLogPublisherCfg> implements
+    ConfigurationChangeListener<FileBasedAccessLogPublisherCfg>
 {
-  private boolean suppressInternalOperations = true;
-
-  private boolean suppressSynchronizationOperations = false;
-
-  private TextWriter writer;
-
-  private FileBasedAccessLogPublisherCfg currentConfig;
 
   /**
-   * Returns an instance of the text access log publisher that will print
-   * all messages to the provided writer. This is used to print the messages
-   * to the console when the server starts up.
-   *
-   * @param writer The text writer where the message will be written to.
-   * @param suppressInternal Indicates whether to suppress internal operations.
-   * @return The instance of the text error log publisher that will print
-   * all messages to standard out.
+   * The category to use when logging responses.
    */
-  public static TextAccessLogPublisher
-      getStartupTextAccessPublisher(TextWriter writer, boolean suppressInternal)
+  private static final String CATEGORY_RESPONSE = "RES";
+
+  /**
+   * The category to use when logging requests.
+   */
+  private static final String CATEGORY_REQUEST = "REQ";
+
+
+
+  /**
+   * Returns an instance of the text access log publisher that will
+   * print all messages to the provided writer. This is used to print
+   * the messages to the console when the server starts up.
+   *
+   * @param writer
+   *          The text writer where the message will be written to.
+   * @param suppressInternal
+   *          Indicates whether to suppress internal operations.
+   * @return The instance of the text error log publisher that will
+   *         print all messages to standard out.
+   */
+  public static TextAccessLogPublisher getStartupTextAccessPublisher(
+      TextWriter writer, boolean suppressInternal)
   {
     TextAccessLogPublisher startupPublisher = new TextAccessLogPublisher();
     startupPublisher.writer = writer;
@@ -94,17 +115,151 @@
     return startupPublisher;
   }
 
+  private FileBasedAccessLogPublisherCfg currentConfig;
+
+  private boolean suppressInternalOperations = true;
+
+  private boolean suppressSynchronizationOperations = false;
+
+  private TextWriter writer;
+
+
+
   /**
    * {@inheritDoc}
    */
-  public boolean isConfigurationAcceptable(AccessLogPublisherCfg configuration,
-                                           List<Message> unacceptableReasons)
+  public ConfigChangeResult applyConfigurationChange(
+      FileBasedAccessLogPublisherCfg config)
   {
-    FileBasedAccessLogPublisherCfg config =
-        (FileBasedAccessLogPublisherCfg) configuration;
-    return isConfigurationChangeAcceptable(config, unacceptableReasons);
+    // Default result code.
+    ResultCode resultCode = ResultCode.SUCCESS;
+    boolean adminActionRequired = false;
+    ArrayList<Message> messages = new ArrayList<Message>();
+
+    suppressInternalOperations = config.isSuppressInternalOperations();
+    suppressSynchronizationOperations = config
+        .isSuppressSynchronizationOperations();
+
+    File logFile = getFileForPath(config.getLogFile());
+    FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
+
+    try
+    {
+      FilePermission perm = FilePermission.decodeUNIXMode(config
+          .getLogFilePermissions());
+
+      boolean writerAutoFlush = config.isAutoFlush()
+          && !config.isAsynchronous();
+
+      TextWriter currentWriter;
+      // Determine the writer we are using. If we were writing
+      // asynchronously, we need to modify the underlying writer.
+      if (writer instanceof AsyncronousTextWriter)
+      {
+        currentWriter = ((AsyncronousTextWriter) writer).getWrappedWriter();
+      }
+      else
+      {
+        currentWriter = writer;
+      }
+
+      if (currentWriter instanceof MultifileTextWriter)
+      {
+        MultifileTextWriter mfWriter = (MultifileTextWriter) currentWriter;
+
+        mfWriter.setNamingPolicy(fnPolicy);
+        mfWriter.setFilePermissions(perm);
+        mfWriter.setAppend(config.isAppend());
+        mfWriter.setAutoFlush(writerAutoFlush);
+        mfWriter.setBufferSize((int) config.getBufferSize());
+        mfWriter.setInterval(config.getTimeInterval());
+
+        mfWriter.removeAllRetentionPolicies();
+        mfWriter.removeAllRotationPolicies();
+
+        for (DN dn : config.getRotationPolicyDNs())
+        {
+          mfWriter.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
+        }
+
+        for (DN dn : config.getRetentionPolicyDNs())
+        {
+          mfWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
+        }
+
+        if (writer instanceof AsyncronousTextWriter && !config.isAsynchronous())
+        {
+          // The asynchronous setting is being turned off.
+          AsyncronousTextWriter asyncWriter = ((AsyncronousTextWriter) writer);
+          writer = mfWriter;
+          asyncWriter.shutdown(false);
+        }
+
+        if (!(writer instanceof AsyncronousTextWriter)
+            && config.isAsynchronous())
+        {
+          // The asynchronous setting is being turned on.
+          AsyncronousTextWriter asyncWriter = new AsyncronousTextWriter(
+              "Asyncronous Text Writer for " + config.dn().toNormalizedString(),
+              config.getQueueSize(), config.isAutoFlush(), mfWriter);
+          writer = asyncWriter;
+        }
+
+        if ((currentConfig.isAsynchronous() && config.isAsynchronous())
+            && (currentConfig.getQueueSize() != config.getQueueSize()))
+        {
+          adminActionRequired = true;
+        }
+
+        currentConfig = config;
+      }
+    }
+    catch (Exception e)
+    {
+      Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(config.dn()
+          .toString(), stackTraceToSingleLineString(e));
+      resultCode = DirectoryServer.getServerErrorResultCode();
+      messages.add(message);
+
+    }
+
+    return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
 
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void close()
+  {
+    writer.shutdown();
+
+    if (currentConfig != null)
+    {
+      currentConfig.removeFileBasedAccessChangeListener(this);
+    }
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public DN getDN()
+  {
+    if (currentConfig != null)
+    {
+      return currentConfig.dn();
+    }
+    else
+    {
+      return null;
+    }
+  }
+
+
+
   /**
    * {@inheritDoc}
    */
@@ -117,68 +272,60 @@
 
     try
     {
-      FilePermission perm =
-          FilePermission.decodeUNIXMode(config.getLogFilePermissions());
+      FilePermission perm = FilePermission.decodeUNIXMode(config
+          .getLogFilePermissions());
 
-      LogPublisherErrorHandler errorHandler =
-          new LogPublisherErrorHandler(config.dn());
+      LogPublisherErrorHandler errorHandler = new LogPublisherErrorHandler(
+          config.dn());
 
-      boolean writerAutoFlush =
-          config.isAutoFlush() && !config.isAsynchronous();
+      boolean writerAutoFlush = config.isAutoFlush()
+          && !config.isAsynchronous();
 
-      MultifileTextWriter writer =
-          new MultifileTextWriter("Multifile Text Writer for " +
-              config.dn().toNormalizedString(),
-                                  config.getTimeInterval(),
-                                  fnPolicy,
-                                  perm,
-                                  errorHandler,
-                                  "UTF-8",
-                                  writerAutoFlush,
-                                  config.isAppend(),
-                                  (int)config.getBufferSize());
+      MultifileTextWriter writer = new MultifileTextWriter(
+          "Multifile Text Writer for " + config.dn().toNormalizedString(),
+          config.getTimeInterval(), fnPolicy, perm, errorHandler, "UTF-8",
+          writerAutoFlush, config.isAppend(), (int) config.getBufferSize());
 
       // Validate retention and rotation policies.
-      for(DN dn : config.getRotationPolicyDNs())
+      for (DN dn : config.getRotationPolicyDNs())
       {
         writer.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
       }
 
-      for(DN dn: config.getRetentionPolicyDNs())
+      for (DN dn : config.getRetentionPolicyDNs())
       {
         writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
       }
 
-      if(config.isAsynchronous())
+      if (config.isAsynchronous())
       {
-        this.writer = new AsyncronousTextWriter("Asyncronous Text Writer for " +
-            config.dn().toNormalizedString(), config.getQueueSize(),
-                                              config.isAutoFlush(),
-                                              writer);
+        this.writer = new AsyncronousTextWriter("Asyncronous Text Writer for "
+            + config.dn().toNormalizedString(), config.getQueueSize(), config
+            .isAutoFlush(), writer);
       }
       else
       {
         this.writer = writer;
       }
     }
-    catch(DirectoryException e)
+    catch (DirectoryException e)
     {
-      Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(
-          config.dn().toString(), String.valueOf(e));
+      Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(config.dn()
+          .toString(), String.valueOf(e));
       throw new InitializationException(message, e);
 
     }
-    catch(IOException e)
+    catch (IOException e)
     {
-      Message message = ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE.get(
-          logFile.toString(), config.dn().toString(), String.valueOf(e));
+      Message message = ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE.get(logFile
+          .toString(), config.dn().toString(), String.valueOf(e));
       throw new InitializationException(message, e);
 
     }
 
     suppressInternalOperations = config.isSuppressInternalOperations();
-    suppressSynchronizationOperations =
-      config.isSuppressSynchronizationOperations();
+    suppressSynchronizationOperations = config
+        .isSuppressSynchronizationOperations();
 
     currentConfig = config;
 
@@ -190,160 +337,469 @@
   /**
    * {@inheritDoc}
    */
-  public boolean isConfigurationChangeAcceptable(
-       FileBasedAccessLogPublisherCfg config, List<Message> unacceptableReasons)
-   {
-     // Make sure the permission is valid.
-     try
-     {
-       FilePermission filePerm =
-           FilePermission.decodeUNIXMode(config.getLogFilePermissions());
-       if(!filePerm.isOwnerWritable())
-       {
-         Message message = ERR_CONFIG_LOGGING_INSANE_MODE.get(
-             config.getLogFilePermissions());
-         unacceptableReasons.add(message);
-         return false;
-       }
-     }
-     catch(DirectoryException e)
-     {
-       Message message = ERR_CONFIG_LOGGING_MODE_INVALID.get(
-               config.getLogFilePermissions(), String.valueOf(e));
-       unacceptableReasons.add(message);
-       return false;
-     }
-
-     return true;
-   }
-
-  /**
-   * {@inheritDoc}
-   */
-   public ConfigChangeResult applyConfigurationChange(
-       FileBasedAccessLogPublisherCfg config)
-   {
-     // Default result code.
-     ResultCode resultCode = ResultCode.SUCCESS;
-     boolean adminActionRequired = false;
-     ArrayList<Message> messages = new ArrayList<Message>();
-
-     suppressInternalOperations = config.isSuppressInternalOperations();
-     suppressSynchronizationOperations =
-       config.isSuppressSynchronizationOperations();
-
-     File logFile = getFileForPath(config.getLogFile());
-     FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
-
-     try
-     {
-       FilePermission perm =
-           FilePermission.decodeUNIXMode(config.getLogFilePermissions());
-
-       boolean writerAutoFlush =
-          config.isAutoFlush() && !config.isAsynchronous();
-
-       TextWriter currentWriter;
-       // Determine the writer we are using. If we were writing asyncronously,
-       // we need to modify the underlaying writer.
-       if(writer instanceof AsyncronousTextWriter)
-       {
-         currentWriter = ((AsyncronousTextWriter)writer).getWrappedWriter();
-       }
-       else
-       {
-         currentWriter = writer;
-       }
-
-       if(currentWriter instanceof MultifileTextWriter)
-       {
-         MultifileTextWriter mfWriter = (MultifileTextWriter)currentWriter;
-
-         mfWriter.setNamingPolicy(fnPolicy);
-         mfWriter.setFilePermissions(perm);
-         mfWriter.setAppend(config.isAppend());
-         mfWriter.setAutoFlush(writerAutoFlush);
-         mfWriter.setBufferSize((int)config.getBufferSize());
-         mfWriter.setInterval(config.getTimeInterval());
-
-         mfWriter.removeAllRetentionPolicies();
-         mfWriter.removeAllRotationPolicies();
-
-         for(DN dn : config.getRotationPolicyDNs())
-         {
-           mfWriter.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
-         }
-
-         for(DN dn: config.getRetentionPolicyDNs())
-         {
-           mfWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
-         }
-
-         if(writer instanceof AsyncronousTextWriter && !config.isAsynchronous())
-         {
-           // The asynronous setting is being turned off.
-           AsyncronousTextWriter asyncWriter = ((AsyncronousTextWriter)writer);
-           writer = mfWriter;
-           asyncWriter.shutdown(false);
-         }
-
-         if(!(writer instanceof AsyncronousTextWriter) &&
-             config.isAsynchronous())
-         {
-           // The asynronous setting is being turned on.
-           AsyncronousTextWriter asyncWriter =
-               new AsyncronousTextWriter("Asyncronous Text Writer for " +
-                   config.dn().toNormalizedString(), config.getQueueSize(),
-                                                     config.isAutoFlush(),
-                                                     mfWriter);
-           writer = asyncWriter;
-         }
-
-         if((currentConfig.isAsynchronous() && config.isAsynchronous()) &&
-             (currentConfig.getQueueSize() != config.getQueueSize()))
-         {
-           adminActionRequired = true;
-         }
-
-         currentConfig = config;
-       }
-     }
-     catch(Exception e)
-     {
-       Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(
-               config.dn().toString(),
-               stackTraceToSingleLineString(e));
-       resultCode = DirectoryServer.getServerErrorResultCode();
-       messages.add(message);
-
-     }
-
-     return new ConfigChangeResult(resultCode, adminActionRequired, messages);
-   }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public void close()
+  public boolean isConfigurationAcceptable(
+      AccessLogPublisherCfg configuration,
+      List<Message> unacceptableReasons)
   {
-    writer.shutdown();
-
-    if(currentConfig != null)
-    {
-      currentConfig.removeFileBasedAccessChangeListener(this);
-    }
+    FileBasedAccessLogPublisherCfg config =
+      (FileBasedAccessLogPublisherCfg) configuration;
+    return isConfigurationChangeAcceptable(config, unacceptableReasons);
   }
 
 
 
   /**
-   * Writes a message to the access logger with information about a new client
-   * connection that has been established, regardless of whether it will be
-   * immediately terminated.
+   * {@inheritDoc}
+   */
+  public boolean isConfigurationChangeAcceptable(
+      FileBasedAccessLogPublisherCfg config, List<Message> unacceptableReasons)
+  {
+    // Make sure the permission is valid.
+    try
+    {
+      FilePermission filePerm = FilePermission.decodeUNIXMode(config
+          .getLogFilePermissions());
+      if (!filePerm.isOwnerWritable())
+      {
+        Message message = ERR_CONFIG_LOGGING_INSANE_MODE.get(config
+            .getLogFilePermissions());
+        unacceptableReasons.add(message);
+        return false;
+      }
+    }
+    catch (DirectoryException e)
+    {
+      Message message = ERR_CONFIG_LOGGING_MODE_INVALID.get(config
+          .getLogFilePermissions(), String.valueOf(e));
+      unacceptableReasons.add(message);
+      return false;
+    }
+
+    return true;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void logAbandonIntermediateMessage(AbandonOperation abandonOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(abandonOperation, "ABANDON", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * abandon request associated with the provided abandon operation.
    *
-   * @param  clientConnection  The client connection that has been established.
+   * @param abandonOperation
+   *          The abandon operation containing the information to use
+   *          to log the abandon request.
+   */
+  public void logAbandonRequest(AbandonOperation abandonOperation)
+  {
+    if (!isLoggable(abandonOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(abandonOperation, "ABANDON", CATEGORY_REQUEST, buffer);
+    buffer.append(" idToAbandon=");
+    buffer.append(abandonOperation.getIDToAbandon());
+    if (abandonOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * result of the provided abandon operation.
+   *
+   * @param abandonOperation
+   *          The abandon operation containing the information to use
+   *          to log the abandon request.
+   */
+  public void logAbandonResult(AbandonOperation abandonOperation)
+  {
+    if (!isLoggable(abandonOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(abandonOperation, "ABANDON", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(abandonOperation.getResultCode().getIntValue());
+    MessageBuilder msg = abandonOperation.getErrorMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" message=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    msg = abandonOperation.getAdditionalLogMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" additionalInfo=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    buffer.append(" etime=");
+    buffer.append(abandonOperation.getProcessingTime());
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void logAddIntermediateMessage(AddOperation addOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(addOperation, "ADD", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * add request associated with the provided add operation.
+   *
+   * @param addOperation
+   *          The add operation containing the information to use to
+   *          log the add request.
+   */
+  public void logAddRequest(AddOperation addOperation)
+  {
+    if (!isLoggable(addOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(addOperation, "ADD", CATEGORY_REQUEST, buffer);
+    buffer.append(" dn=\"");
+    addOperation.getRawEntryDN().toString(buffer);
+    buffer.append("\"");
+    if (addOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * add response associated with the provided add operation.
+   *
+   * @param addOperation
+   *          The add operation containing the information to use to
+   *          log the add response.
+   */
+  public void logAddResponse(AddOperation addOperation)
+  {
+    if (!isLoggable(addOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(addOperation, "ADD", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(addOperation.getResultCode().getIntValue());
+
+    MessageBuilder msg = addOperation.getErrorMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" message=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    msg = addOperation.getAdditionalLogMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" additionalInfo=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    DN proxiedAuthDN = addOperation.getProxiedAuthorizationDN();
+    if (proxiedAuthDN != null)
+    {
+      buffer.append(" authzDN=\"");
+      proxiedAuthDN.toString(buffer);
+      buffer.append('\"');
+    }
+
+    buffer.append(" etime=");
+    buffer.append(addOperation.getProcessingTime());
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void logBindIntermediateMessage(BindOperation bindOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(bindOperation, "BIND", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * bind request associated with the provided bind operation.
+   *
+   * @param bindOperation
+   *          The bind operation with the information to use to log
+   *          the bind request.
+   */
+  public void logBindRequest(BindOperation bindOperation)
+  {
+    if (!isLoggable(bindOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(bindOperation, "BIND", CATEGORY_REQUEST, buffer);
+
+    switch (bindOperation.getAuthenticationType())
+    {
+    case SIMPLE:
+      buffer.append(" type=SIMPLE");
+      break;
+    case SASL:
+      buffer.append(" type=SASL mechanism=");
+      buffer.append(bindOperation.getSASLMechanism());
+      break;
+    default:
+      buffer.append(" type=");
+      buffer.append(bindOperation.getAuthenticationType());
+      break;
+    }
+
+    buffer.append(" dn=\"");
+    bindOperation.getRawBindDN().toString(buffer);
+    buffer.append("\"");
+    if (bindOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * bind response associated with the provided bind operation.
+   *
+   * @param bindOperation
+   *          The bind operation containing the information to use to
+   *          log the bind response.
+   */
+  public void logBindResponse(BindOperation bindOperation)
+  {
+    if (!isLoggable(bindOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(bindOperation, "BIND", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(bindOperation.getResultCode().getIntValue());
+
+    MessageBuilder msg = bindOperation.getErrorMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" message=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    Message failureMessage = bindOperation.getAuthFailureReason();
+    if (failureMessage != null)
+    {
+      buffer.append(" authFailureID=");
+      buffer.append(failureMessage.getDescriptor().getId());
+      buffer.append(" authFailureReason=\"");
+      buffer.append(failureMessage);
+      buffer.append('\"');
+    }
+
+    msg = bindOperation.getAdditionalLogMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" additionalInfo=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    if (bindOperation.getResultCode() == ResultCode.SUCCESS)
+    {
+      AuthenticationInfo authInfo = bindOperation.getAuthenticationInfo();
+      if (authInfo != null)
+      {
+        DN authDN = authInfo.getAuthenticationDN();
+        if (authDN != null)
+        {
+          buffer.append(" authDN=\"");
+          authDN.toString(buffer);
+          buffer.append('\"');
+
+          DN authzDN = authInfo.getAuthorizationDN();
+          if (!authDN.equals(authzDN))
+          {
+            buffer.append(" authzDN=\"");
+            if (authzDN != null)
+            {
+              authzDN.toString(buffer);
+            }
+            buffer.append('\"');
+          }
+        }
+        else
+        {
+          buffer.append(" authDN=\"\"");
+        }
+      }
+    }
+
+    buffer.append(" etime=");
+    long etime = bindOperation.getProcessingNanoTime();
+    if (etime <= -1)
+    {
+      etime = bindOperation.getProcessingTime();
+    }
+    buffer.append(etime);
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void logCompareIntermediateMessage(CompareOperation compareOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(compareOperation, "COMPARE", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * compare request associated with the provided compare operation.
+   *
+   * @param compareOperation
+   *          The compare operation containing the information to use
+   *          to log the compare request.
+   */
+  public void logCompareRequest(CompareOperation compareOperation)
+  {
+    if (!isLoggable(compareOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(compareOperation, "COMPARE", CATEGORY_REQUEST, buffer);
+    buffer.append(" dn=\"");
+    compareOperation.getRawEntryDN().toString(buffer);
+    buffer.append("\" attr=");
+    buffer.append(compareOperation.getAttributeType());
+    if (compareOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * compare response associated with the provided compare operation.
+   *
+   * @param compareOperation
+   *          The compare operation containing the information to use
+   *          to log the compare response.
+   */
+  public void logCompareResponse(CompareOperation compareOperation)
+  {
+    if (!isLoggable(compareOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(compareOperation, "COMPARE", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(compareOperation.getResultCode().getIntValue());
+
+    MessageBuilder msg = compareOperation.getErrorMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" message=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    msg = compareOperation.getAdditionalLogMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" additionalInfo=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    DN proxiedAuthDN = compareOperation.getProxiedAuthorizationDN();
+    if (proxiedAuthDN != null)
+    {
+      buffer.append(" authzDN=\"");
+      proxiedAuthDN.toString(buffer);
+      buffer.append('\"');
+    }
+
+    buffer.append(" etime=");
+    long etime = compareOperation.getProcessingNanoTime();
+    if (etime <= -1)
+    {
+      etime = compareOperation.getProcessingTime();
+    }
+    buffer.append(etime);
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about a
+   * new client connection that has been established, regardless of
+   * whether it will be immediately terminated.
+   *
+   * @param clientConnection
+   *          The client connection that has been established.
    */
   public void logConnect(ClientConnection clientConnection)
   {
@@ -360,9 +816,9 @@
     buffer.append(" CONNECT conn=");
     buffer.append(connectionID);
     buffer.append(" from=");
-    buffer.append(clientConnection.getClientAddress());
+    buffer.append(clientConnection.getClientHostPort());
     buffer.append(" to=");
-    buffer.append(clientConnection.getServerAddress());
+    buffer.append(clientConnection.getServerHostPort());
     buffer.append(" protocol=");
     buffer.append(clientConnection.getProtocol());
 
@@ -371,19 +827,118 @@
   }
 
 
+
+  /**
+   * {@inheritDoc}
+   */
+  public void logDeleteIntermediateMessage(DeleteOperation deleteOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(deleteOperation, "DELETE", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * delete request associated with the provided delete operation.
+   *
+   * @param deleteOperation
+   *          The delete operation with the information to use to log
+   *          the delete request.
+   */
+  public void logDeleteRequest(DeleteOperation deleteOperation)
+  {
+    if (!isLoggable(deleteOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(deleteOperation, "DELETE", CATEGORY_REQUEST, buffer);
+    buffer.append(" dn=\"");
+    deleteOperation.getRawEntryDN().toString(buffer);
+    buffer.append("\"");
+    if (deleteOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * delete response associated with the provided delete operation.
+   *
+   * @param deleteOperation
+   *          The delete operation containing the information to use
+   *          to log the delete response.
+   */
+  public void logDeleteResponse(DeleteOperation deleteOperation)
+  {
+    if (!isLoggable(deleteOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(deleteOperation, "DELETE", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(deleteOperation.getResultCode().getIntValue());
+
+    MessageBuilder msg = deleteOperation.getErrorMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" message=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    msg = deleteOperation.getAdditionalLogMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" additionalInfo=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    DN proxiedAuthDN = deleteOperation.getProxiedAuthorizationDN();
+    if (proxiedAuthDN != null)
+    {
+      buffer.append(" authzDN=\"");
+      proxiedAuthDN.toString(buffer);
+      buffer.append('\"');
+    }
+
+    buffer.append(" etime=");
+    long etime = deleteOperation.getProcessingNanoTime();
+    if (etime <= -1)
+    {
+      etime = deleteOperation.getProcessingTime();
+    }
+    buffer.append(etime);
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
   /**
    * Writes a message to the access logger with information about the
    * termination of an existing client connection.
    *
-   * @param  clientConnection  The client connection that has been terminated.
-   * @param  disconnectReason  A generic disconnect reason for the connection
-   *                           termination.
-   * @param  message           A human-readable message that can provide
-   *                           additional information about the disconnect.
+   * @param clientConnection
+   *          The client connection that has been terminated.
+   * @param disconnectReason
+   *          A generic disconnect reason for the connection
+   *          termination.
+   * @param message
+   *          A human-readable message that can provide additional
+   *          information about the disconnect.
    */
   public void logDisconnect(ClientConnection clientConnection,
-                            DisconnectReason disconnectReason,
-                            Message message)
+      DisconnectReason disconnectReason, Message message)
   {
     long connectionID = clientConnection.getConnectionID();
     if (connectionID < 0 && suppressInternalOperations)
@@ -413,766 +968,94 @@
 
 
   /**
-   * Writes a message to the access logger with information about the abandon
-   * request associated with the provided abandon operation.
-   *
-   * @param  abandonOperation  The abandon operation containing the information
-   *                           to use to log the abandon request.
+   * {@inheritDoc}
    */
-  public void logAbandonRequest(AbandonOperation abandonOperation)
+  public void logExtendedIntermediateMessage(
+      ExtendedOperation extendedOperation, String category,
+      Map<String, String> content)
   {
-    long connectionID = abandonOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (abandonOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" ABANDON conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(abandonOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(abandonOperation.getMessageID());
-    buffer.append(" idToAbandon=");
-    buffer.append(abandonOperation.getIDToAbandon());
-    if (abandonOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
-
-    writer.writeRecord(buffer.toString());
-  }
-
-  /**
-   * Writes a message to the access logger with information about the result
-   * of the provided abandon operation.
-   *
-   * @param  abandonOperation  The abandon operation containing the information
-   *                           to use to log the abandon request.
-   */
-  public void logAbandonResult(AbandonOperation abandonOperation)
-  {
-    long connectionID = abandonOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (abandonOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" ABANDON conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(abandonOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(abandonOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(abandonOperation.getResultCode());
-    buffer.append("\"");
-    MessageBuilder msg = abandonOperation.getErrorMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" message=\"");
-      buffer.append(msg);
-      buffer.append("\"");
-    }
-
-    msg = abandonOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append("\"");
-    }
-
-    buffer.append(" etime=");
-    buffer.append(abandonOperation.getProcessingTime());
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the add
-   * request associated with the provided add operation.
-   *
-   * @param  addOperation  The add operation containing the information to use
-   *                       to log the add request.
-   */
-  public void logAddRequest(AddOperation addOperation)
-  {
-    long connectionID = addOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (addOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" ADD conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(addOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(addOperation.getMessageID());
-    buffer.append(" dn=\"");
-    addOperation.getRawEntryDN().toString(buffer);
-    buffer.append("\"");
-    if (addOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
-
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the add
-   * response associated with the provided add operation.
-   *
-   * @param  addOperation  The add operation containing the information to use
-   *                       to log the add response.
-   */
-  public void logAddResponse(AddOperation addOperation)
-  {
-    long connectionID = addOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (addOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" ADD conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(addOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(addOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(addOperation.getResultCode());
-
-    MessageBuilder msg = addOperation.getErrorMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" message=\"");
-      buffer.append(msg);
-    }
-
-    msg = addOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" additionalInfo=\"");
-      buffer.append(msg);
-    }
-
-    DN proxiedAuthDN = addOperation.getProxiedAuthorizationDN();
-    if (proxiedAuthDN != null)
-    {
-      buffer.append("\" authzDN=\"");
-      proxiedAuthDN.toString(buffer);
-    }
-
-    buffer.append("\" etime=");
-    buffer.append(addOperation.getProcessingTime());
-
-    writer.writeRecord(buffer.toString());
+    logIntermediateMessage(extendedOperation, "EXTENDED", category, content);
   }
 
 
 
   /**
-   * Writes a message to the access logger with information about the bind
-   * request associated with the provided bind operation.
+   * Writes a message to the access logger with information about the
+   * extended request associated with the provided extended operation.
    *
-   * @param  bindOperation  The bind operation with the information to use
-   *                        to log the bind request.
-   */
-  public void logBindRequest(BindOperation bindOperation)
-  {
-    long connectionID = bindOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (bindOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" BIND conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(bindOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(bindOperation.getMessageID());
-
-    switch (bindOperation.getAuthenticationType())
-    {
-      case SIMPLE:
-        buffer.append(" type=SIMPLE");
-        break;
-      case SASL:
-        buffer.append(" type=SASL mechanism=");
-        buffer.append(bindOperation.getSASLMechanism());
-        break;
-      default:
-        buffer.append(" type=");
-        buffer.append(bindOperation.getAuthenticationType());
-        break;
-    }
-
-    buffer.append(" dn=\"");
-    bindOperation.getRawBindDN().toString(buffer);
-    buffer.append("\"");
-    if (bindOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
-
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the bind
-   * response associated with the provided bind operation.
-   *
-   * @param  bindOperation  The bind operation containing the information to use
-   *                        to log the bind response.
-   */
-  public void logBindResponse(BindOperation bindOperation)
-  {
-    long connectionID = bindOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (bindOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" BIND conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(bindOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(bindOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(bindOperation.getResultCode());
-
-    MessageBuilder msg = bindOperation.getErrorMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" message=\"");
-      buffer.append(msg);
-    }
-
-    Message failureMessage = bindOperation.getAuthFailureReason();
-    if (failureMessage != null)
-    {
-      buffer.append("\" authFailureID=");
-      buffer.append(failureMessage.getDescriptor().getId());
-      buffer.append(" authFailureReason=\"");
-      buffer.append(failureMessage);
-    }
-
-    msg = bindOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" additionalInfo=\"");
-      buffer.append(msg);
-    }
-
-    if (bindOperation.getResultCode() == ResultCode.SUCCESS)
-    {
-      AuthenticationInfo authInfo = bindOperation.getAuthenticationInfo();
-      if (authInfo != null)
-      {
-        DN authDN = authInfo.getAuthenticationDN();
-        buffer.append("\" authDN=\"");
-        if (authDN != null)
-        {
-          authDN.toString(buffer);
-
-          DN authzDN = authInfo.getAuthorizationDN();
-          if (! authDN.equals(authzDN))
-          {
-            buffer.append("\" authzDN=\"");
-            if (authzDN != null)
-            {
-              authzDN.toString(buffer);
-            }
-          }
-        }
-      }
-    }
-
-    buffer.append("\" etime=");
-    long etime = bindOperation.getProcessingNanoTime();
-    if(etime <= -1)
-    {
-      etime = bindOperation.getProcessingTime();
-    }
-    buffer.append(etime);
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the compare
-   * request associated with the provided compare operation.
-   *
-   * @param  compareOperation  The compare operation containing the information
-   *                           to use to log the compare request.
-   */
-  public void logCompareRequest(CompareOperation compareOperation)
-  {
-    long connectionID = compareOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (compareOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" COMPARE conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(compareOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(compareOperation.getMessageID());
-    buffer.append(" dn=\"");
-    compareOperation.getRawEntryDN().toString(buffer);
-    buffer.append("\" attr=");
-    buffer.append(compareOperation.getAttributeType());
-    if (compareOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
-
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the compare
-   * response associated with the provided compare operation.
-   *
-   * @param  compareOperation  The compare operation containing the information
-   *                           to use to log the compare response.
-   */
-  public void logCompareResponse(CompareOperation compareOperation)
-  {
-    long connectionID = compareOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (compareOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" COMPARE conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(compareOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(compareOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(compareOperation.getResultCode());
-
-    MessageBuilder msg = compareOperation.getErrorMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" message=\"");
-      buffer.append(msg);
-    }
-
-    msg = compareOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" additionalInfo=\"");
-      buffer.append(msg);
-    }
-
-    DN proxiedAuthDN = compareOperation.getProxiedAuthorizationDN();
-    if (proxiedAuthDN != null)
-    {
-      buffer.append("\" authzDN=\"");
-      proxiedAuthDN.toString(buffer);
-    }
-
-    buffer.append("\" etime=");
-    long etime = compareOperation.getProcessingNanoTime();
-    if(etime <= -1)
-    {
-      etime = compareOperation.getProcessingTime();
-    }
-    buffer.append(etime);
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the delete
-   * request associated with the provided delete operation.
-   *
-   * @param  deleteOperation  The delete operation with the information to
-   *                          use to log the delete request.
-   */
-  public void logDeleteRequest(DeleteOperation deleteOperation)
-  {
-    long connectionID = deleteOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (deleteOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" DELETE conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(deleteOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(deleteOperation.getMessageID());
-    buffer.append(" dn=\"");
-    deleteOperation.getRawEntryDN().toString(buffer);
-    buffer.append("\"");
-    if (deleteOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
-
-
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the delete
-   * response associated with the provided delete operation.
-   *
-   * @param  deleteOperation The delete operation containing the information to
-   *                           use to log the delete response.
-   */
-  public void logDeleteResponse(DeleteOperation deleteOperation)
-  {
-    long connectionID = deleteOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (deleteOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" DELETE conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(deleteOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(deleteOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(deleteOperation.getResultCode());
-
-    MessageBuilder msg = deleteOperation.getErrorMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" message=\"");
-      buffer.append(msg);
-    }
-
-    msg = deleteOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" additionalInfo=\"");
-      buffer.append(msg);
-    }
-
-    DN proxiedAuthDN = deleteOperation.getProxiedAuthorizationDN();
-    if (proxiedAuthDN != null)
-    {
-      buffer.append("\" authzDN=\"");
-      proxiedAuthDN.toString(buffer);
-    }
-
-    buffer.append("\" etime=");
-    long etime = deleteOperation.getProcessingNanoTime();
-    if(etime <= -1)
-    {
-      etime = deleteOperation.getProcessingTime();
-    }
-    buffer.append(etime);
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-
-  /**
-   * Writes a message to the access logger with information about the extended
-   * request associated with the provided extended operation.
-   *
-   * @param  extendedOperation  The extended operation containing the
-   *                            information to use to log the extended request.
+   * @param extendedOperation
+   *          The extended operation containing the information to use
+   *          to log the extended request.
    */
   public void logExtendedRequest(ExtendedOperation extendedOperation)
   {
-    long connectionID = extendedOperation.getConnectionID();
-    if (connectionID < 0)
+    if (!isLoggable(extendedOperation))
     {
-      // This is an internal operation.
-      if (extendedOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
+      return;
     }
+
     StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" EXTENDED conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(extendedOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(extendedOperation.getMessageID());
+    appendHeader(extendedOperation, "EXTENDED", CATEGORY_REQUEST, buffer);
     buffer.append(" oid=\"");
     buffer.append(extendedOperation.getRequestOID());
     buffer.append("\"");
     if (extendedOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
 
-
     writer.writeRecord(buffer.toString());
   }
 
 
 
   /**
-   * Writes a message to the access logger with information about the extended
-   * response associated with the provided extended operation.
+   * Writes a message to the access logger with information about the
+   * extended response associated with the provided extended
+   * operation.
    *
-   * @param  extendedOperation  The extended operation containing the
-   *                            info to use to log the extended response.
+   * @param extendedOperation
+   *          The extended operation containing the info to use to log
+   *          the extended response.
    */
   public void logExtendedResponse(ExtendedOperation extendedOperation)
   {
-    long connectionID = extendedOperation.getConnectionID();
-    if (connectionID < 0)
+    if (!isLoggable(extendedOperation))
     {
-      // This is an internal operation.
-      if (extendedOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
+      return;
     }
+
     StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" EXTENDED conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(extendedOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(extendedOperation.getMessageID());
+    appendHeader(extendedOperation, "EXTENDED", CATEGORY_RESPONSE, buffer);
 
     String oid = extendedOperation.getResponseOID();
     if (oid != null)
     {
       buffer.append(" oid=\"");
       buffer.append(oid);
-      buffer.append("\"");
+      buffer.append('\"');
     }
 
-    buffer.append(" result=\"");
-    buffer.append(extendedOperation.getResultCode());
+    buffer.append(" result=");
+    buffer.append(extendedOperation.getResultCode().getIntValue());
 
     MessageBuilder msg = extendedOperation.getErrorMessage();
     if ((msg != null) && (msg.length() > 0))
     {
-      buffer.append("\" message=\"");
+      buffer.append(" message=\"");
       buffer.append(msg);
+      buffer.append('\"');
     }
 
     msg = extendedOperation.getAdditionalLogMessage();
     if ((msg != null) && (msg.length() > 0))
     {
-      buffer.append("\" additionalInfo=\"");
+      buffer.append(" additionalInfo=\"");
       buffer.append(msg);
+      buffer.append('\"');
     }
 
-    buffer.append("\" etime=");
+    buffer.append(" etime=");
     long etime = extendedOperation.getProcessingNanoTime();
-    if(etime <= -1)
+    if (etime <= -1)
     {
       etime = extendedOperation.getProcessingTime();
     }
@@ -1184,168 +1067,35 @@
 
 
   /**
-   * Writes a message to the access logger with information about the modify
-   * request associated with the provided modify operation.
-   *
-   * @param  modifyOperation The modify operation containing the information to
-   *                         use to log the modify request.
+   * {@inheritDoc}
    */
-  public void logModifyRequest(ModifyOperation modifyOperation)
+  public void logModifyDNIntermediateMessage(
+      ModifyDNOperation modifyDNOperation, String category,
+      Map<String, String> content)
   {
-    long connectionID = modifyOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // This is an internal operation.
-      if (modifyOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" MODIFY conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(modifyOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(modifyOperation.getMessageID());
-    buffer.append(" dn=\"");
-    modifyOperation.getRawEntryDN().toString(buffer);
-    buffer.append("\"");
-    if (modifyOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
-
-
-    writer.writeRecord(buffer.toString());
+    logIntermediateMessage(modifyDNOperation, "MODIFY", category, content);
   }
 
 
 
   /**
-   * Writes a message to the access logger with information about the modify
-   * response associated with the provided modify operation.
+   * Writes a message to the access logger with information about the
+   * modify DN request associated with the provided modify DN
+   * operation.
    *
-   * @param  modifyOperation The modify operation containing the information to
-   *                         use to log the modify response.
-   */
-  public void logModifyResponse(ModifyOperation modifyOperation)
-  {
-    long connectionID = modifyOperation.getConnectionID();
-    if (connectionID < 0)
-    {
-      // this is an internal operation
-      if (modifyOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
-    }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" MODIFY conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(modifyOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(modifyOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(modifyOperation.getResultCode());
-
-    MessageBuilder msg = modifyOperation.getErrorMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" message=\"");
-      buffer.append(msg);
-    }
-
-    msg = modifyOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append("\" additionalInfo=\"");
-      buffer.append(msg);
-    }
-
-    DN proxiedAuthDN = modifyOperation.getProxiedAuthorizationDN();
-    if (proxiedAuthDN != null)
-    {
-      buffer.append("\" authzDN=\"");
-      proxiedAuthDN.toString(buffer);
-    }
-
-    buffer.append("\" etime=");
-    long etime = modifyOperation.getProcessingNanoTime();
-    if(etime <= -1)
-    {
-      etime = modifyOperation.getProcessingTime();
-    }
-    buffer.append(etime);
-
-    writer.writeRecord(buffer.toString());
-  }
-
-
-
-  /**
-   * Writes a message to the access logger with information about the modify DN
-   * request associated with the provided modify DN operation.
-   *
-   * @param  modifyDNOperation  The modify DN operation containing the
-   *                            info to use to log the modify DN request.
+   * @param modifyDNOperation
+   *          The modify DN operation containing the info to use to
+   *          log the modify DN request.
    */
   public void logModifyDNRequest(ModifyDNOperation modifyDNOperation)
   {
-    long connectionID = modifyDNOperation.getConnectionID();
-    if (connectionID < 0)
+    if (!isLoggable(modifyDNOperation))
     {
-      // This is an internal operation.
-      if (modifyDNOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
+      return;
     }
+
     StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" MODIFYDN conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(modifyDNOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(modifyDNOperation.getMessageID());
+    appendHeader(modifyDNOperation, "MODIFYDN", CATEGORY_REQUEST, buffer);
     buffer.append(" dn=\"");
     modifyDNOperation.getRawEntryDN().toString(buffer);
     buffer.append("\" newRDN=\"");
@@ -1362,78 +1112,59 @@
     if (modifyDNOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
 
-
     writer.writeRecord(buffer.toString());
   }
 
 
 
   /**
-   * Writes a message to the access logger with information about the modify DN
-   * response associated with the provided modify DN operation.
+   * Writes a message to the access logger with information about the
+   * modify DN response associated with the provided modify DN
+   * operation.
    *
-   * @param  modifyDNOperation  The modify DN operation containing the
-   *                            information to use to log the modify DN
-   *                            response.
+   * @param modifyDNOperation
+   *          The modify DN operation containing the information to
+   *          use to log the modify DN response.
    */
   public void logModifyDNResponse(ModifyDNOperation modifyDNOperation)
   {
-    long connectionID = modifyDNOperation.getConnectionID();
-    if (connectionID < 0)
+    if (!isLoggable(modifyDNOperation))
     {
-      // This is an internal operation.
-      if (modifyDNOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
+      return;
     }
+
     StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" MODIFYDN conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(modifyDNOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(modifyDNOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(modifyDNOperation.getResultCode());
+    appendHeader(modifyDNOperation, "MODIFYDN", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(modifyDNOperation.getResultCode().getIntValue());
 
     MessageBuilder msg = modifyDNOperation.getErrorMessage();
     if ((msg != null) && (msg.length() > 0))
     {
-      buffer.append("\" message=\"");
+      buffer.append(" message=\"");
       buffer.append(msg);
+      buffer.append('\"');
     }
 
     msg = modifyDNOperation.getAdditionalLogMessage();
     if ((msg != null) && (msg.length() > 0))
     {
-      buffer.append("\" additionalInfo=\"");
+      buffer.append(" additionalInfo=\"");
       buffer.append(msg);
+      buffer.append('\"');
     }
 
     DN proxiedAuthDN = modifyDNOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
     {
-      buffer.append("\" authzDN=\"");
+      buffer.append(" authzDN=\"");
       proxiedAuthDN.toString(buffer);
+      buffer.append('\"');
     }
 
-    buffer.append("\" etime=");
+    buffer.append(" etime=");
     long etime = modifyDNOperation.getProcessingNanoTime();
-    if(etime <= -1)
+    if (etime <= -1)
     {
       etime = modifyDNOperation.getProcessingTime();
     }
@@ -1443,44 +1174,131 @@
   }
 
 
+
   /**
-   * Writes a message to the access logger with information about the search
-   * request associated with the provided search operation.
+   * {@inheritDoc}
+   */
+  public void logModifyIntermediateMessage(ModifyOperation modifyOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(modifyOperation, "MODIFY", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * modify request associated with the provided modify operation.
    *
-   * @param  searchOperation  The search operation containing the info to
-   *                          use to log the search request.
+   * @param modifyOperation
+   *          The modify operation containing the information to use
+   *          to log the modify request.
+   */
+  public void logModifyRequest(ModifyOperation modifyOperation)
+  {
+    if (!isLoggable(modifyOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(modifyOperation, "MODIFY", CATEGORY_REQUEST, buffer);
+    buffer.append(" dn=\"");
+    modifyOperation.getRawEntryDN().toString(buffer);
+    buffer.append("\"");
+    if (modifyOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * modify response associated with the provided modify operation.
+   *
+   * @param modifyOperation
+   *          The modify operation containing the information to use
+   *          to log the modify response.
+   */
+  public void logModifyResponse(ModifyOperation modifyOperation)
+  {
+    if (!isLoggable(modifyOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(modifyOperation, "MODIFY", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(modifyOperation.getResultCode().getIntValue());
+
+    MessageBuilder msg = modifyOperation.getErrorMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" message=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    msg = modifyOperation.getAdditionalLogMessage();
+    if ((msg != null) && (msg.length() > 0))
+    {
+      buffer.append(" additionalInfo=\"");
+      buffer.append(msg);
+      buffer.append('\"');
+    }
+
+    DN proxiedAuthDN = modifyOperation.getProxiedAuthorizationDN();
+    if (proxiedAuthDN != null)
+    {
+      buffer.append(" authzDN=\"");
+      proxiedAuthDN.toString(buffer);
+      buffer.append('\"');
+    }
+
+    buffer.append(" etime=");
+    long etime = modifyOperation.getProcessingNanoTime();
+    if (etime <= -1)
+    {
+      etime = modifyOperation.getProcessingTime();
+    }
+    buffer.append(etime);
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  public void logSearchIntermediateMessage(SearchOperation searchOperation,
+      String category, Map<String, String> content)
+  {
+    logIntermediateMessage(searchOperation, "SEARCH", category, content);
+  }
+
+
+
+  /**
+   * Writes a message to the access logger with information about the
+   * search request associated with the provided search operation.
+   *
+   * @param searchOperation
+   *          The search operation containing the info to use to log
+   *          the search request.
    */
   public void logSearchRequest(SearchOperation searchOperation)
   {
-    long connectionID = searchOperation.getConnectionID();
-    if (connectionID < 0)
+    if (!isLoggable(searchOperation))
     {
-      // This is an internal operation.
-      if (searchOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
+      return;
     }
+
     StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" SEARCH conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(searchOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(searchOperation.getMessageID());
+    appendHeader(searchOperation, "SEARCH", CATEGORY_REQUEST, buffer);
     buffer.append(" base=\"");
     searchOperation.getRawBaseDN().toString(buffer);
     buffer.append("\" scope=");
@@ -1510,93 +1328,40 @@
     if (searchOperation.isSynchronizationOperation())
       buffer.append(" type=synchronization");
 
-
     writer.writeRecord(buffer.toString());
   }
 
 
-  /**
-   * Writes a message to the access logger with information about the search
-   * result entry that matches the criteria associated with the provided search
-   * operation.
-   *
-   * @param  searchOperation  The search operation with which the search result
-   *                          entry is associated.
-   * @param  searchEntry      The search result entry to be logged.
-   */
-  public void logSearchResultEntry(SearchOperation searchOperation,
-                                     SearchResultEntry searchEntry)
-  {
-    // NYI
-  }
-
-
-  /**
-   * Writes a message to the access logger with information about the search
-   * result reference returned while processing the associated search
-   * operation.
-   *
-   * @param  searchOperation  The search operation with which the search result
-   *                          reference is associated.
-   * @param  searchReference  The search result reference to be logged.
-   */
-  public void logSearchResultReference(SearchOperation searchOperation,
-                            SearchResultReference searchReference)
-  {
-    // NYI
-  }
-
-
 
   /**
    * Writes a message to the access logger with information about the
    * completion of the provided search operation.
    *
-   * @param  searchOperation  The search operation containing the information
-   *                          to use to log the search result done message.
+   * @param searchOperation
+   *          The search operation containing the information to use
+   *          to log the search result done message.
    */
   public void logSearchResultDone(SearchOperation searchOperation)
   {
-    long connectionID = searchOperation.getConnectionID();
-    if (connectionID < 0)
+    if (!isLoggable(searchOperation))
     {
-      // This is an internal operation.
-      if (searchOperation.isSynchronizationOperation())
-      {
-        if (suppressSynchronizationOperations)
-        {
-          return;
-        }
-      }
-      else
-      {
-        if (suppressInternalOperations)
-        {
-          return;
-        }
-      }
+      return;
     }
+
     StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" SEARCH conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(searchOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(searchOperation.getMessageID());
-    buffer.append(" result=\"");
-    buffer.append(searchOperation.getResultCode());
+    appendHeader(searchOperation, "SEARCH", CATEGORY_RESPONSE, buffer);
+    buffer.append(" result=");
+    buffer.append(searchOperation.getResultCode().getIntValue());
 
     MessageBuilder msg = searchOperation.getErrorMessage();
     if ((msg != null) && (msg.length() > 0))
     {
-      buffer.append("\" message=\"");
+      buffer.append(" message=\"");
       buffer.append(msg);
+      buffer.append('\"');
     }
 
-    buffer.append("\" nentries=");
+    buffer.append(" nentries=");
     buffer.append(searchOperation.getEntriesSent());
 
     msg = searchOperation.getAdditionalLogMessage();
@@ -1604,7 +1369,7 @@
     {
       buffer.append(" additionalInfo=\"");
       buffer.append(msg);
-      buffer.append("\"");
+      buffer.append('\"');
     }
 
     DN proxiedAuthDN = searchOperation.getProxiedAuthorizationDN();
@@ -1612,12 +1377,12 @@
     {
       buffer.append(" authzDN=\"");
       proxiedAuthDN.toString(buffer);
-      buffer.append("\"");
+      buffer.append('\"');
     }
 
     buffer.append(" etime=");
     long etime = searchOperation.getProcessingNanoTime();
-    if(etime <= -1)
+    if (etime <= -1)
     {
       etime = searchOperation.getProcessingTime();
     }
@@ -1629,63 +1394,97 @@
 
 
   /**
-   * Writes a message to the access logger with information about the unbind
-   * request associated with the provided unbind operation.
+   * Writes a message to the access logger with information about the
+   * unbind request associated with the provided unbind operation.
    *
-   * @param  unbindOperation  The unbind operation containing the info to
-   *                          use to log the unbind request.
+   * @param unbindOperation
+   *          The unbind operation containing the info to use to log
+   *          the unbind request.
    */
   public void logUnbind(UnbindOperation unbindOperation)
   {
-    long connectionID = unbindOperation.getConnectionID();
+    if (!isLoggable(unbindOperation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(unbindOperation, "UNBIND", CATEGORY_REQUEST, buffer);
+    if (unbindOperation.isSynchronizationOperation())
+      buffer.append(" type=synchronization");
+
+    writer.writeRecord(buffer.toString());
+  }
+
+
+
+  // Appends the common log header information to the provided buffer.
+  private void appendHeader(Operation operation, String opType,
+      String category, StringBuilder buffer)
+  {
+    buffer.append("[");
+    buffer.append(TimeThread.getLocalTime());
+    buffer.append("] ");
+    buffer.append(opType);
+    buffer.append(" ");
+    buffer.append(category);
+    buffer.append(" conn=");
+    buffer.append(operation.getConnectionID());
+    buffer.append(" op=");
+    buffer.append(operation.getOperationID());
+    buffer.append(" msgID=");
+    buffer.append(operation.getMessageID());
+  }
+
+
+
+  // Determines whether the provided operation should be logged.
+  private boolean isLoggable(Operation operation)
+  {
+    long connectionID = operation.getConnectionID();
     if (connectionID < 0)
     {
       // This is an internal operation.
-      if (unbindOperation.isSynchronizationOperation())
+      if (operation.isSynchronizationOperation())
       {
         if (suppressSynchronizationOperations)
         {
-          return;
+          return false;
         }
       }
       else
       {
         if (suppressInternalOperations)
         {
-          return;
+          return false;
         }
       }
     }
-    StringBuilder buffer = new StringBuilder(50);
-    buffer.append("[");
-    buffer.append(TimeThread.getLocalTime());
-    buffer.append("]");
-    buffer.append(" UNBIND conn=");
-    buffer.append(connectionID);
-    buffer.append(" op=");
-    buffer.append(unbindOperation.getOperationID());
-    buffer.append(" msgID=");
-    buffer.append(unbindOperation.getMessageID());
-    if (unbindOperation.isSynchronizationOperation())
-      buffer.append(" type=synchronization");
+    return true;
+  }
 
 
+
+  // Writes an intermediate message to the log.
+  private void logIntermediateMessage(Operation operation, String opType,
+      String category, Map<String, String> content)
+  {
+    if (!isLoggable(operation))
+    {
+      return;
+    }
+
+    StringBuilder buffer = new StringBuilder(50);
+    appendHeader(operation, opType, category, buffer);
+
+    for (Map.Entry<String, String> entry : content.entrySet())
+    {
+      buffer.append(' ');
+      buffer.append(entry.getKey());
+      buffer.append('=');
+      buffer.append(entry.getValue());
+    }
+
     writer.writeRecord(buffer.toString());
   }
-
-  /**
-   * {@inheritDoc}
-   */
-  public DN getDN()
-  {
-    if(currentConfig != null)
-    {
-      return currentConfig.dn();
-    }
-    else
-    {
-      return null;
-    }
-  }
 }
-

--
Gitblit v1.10.0