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

boli
03.55.2007 d755882f59202fe62b2ad5a141b3c044c1898aa6
opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
File was renamed from opends/src/server/org/opends/server/loggers/DirectoryAccessLogger.java
@@ -29,22 +29,10 @@
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.*;
import org.opends.server.api.AccessLogger;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConfigurableComponent;
import org.opends.server.config.BooleanConfigAttribute;
import org.opends.server.config.ConfigAttribute;
import org.opends.server.config.ConfigEntry;
import org.opends.server.api.*;
import org.opends.server.config.ConfigException;
import org.opends.server.config.StringConfigAttribute;
import org.opends.server.core.AbandonOperation;
import org.opends.server.core.AddOperation;
import org.opends.server.core.BindOperation;
@@ -56,79 +44,348 @@
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.SearchOperation;
import org.opends.server.core.UnbindOperation;
import org.opends.server.types.ByteString;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.DN;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
import org.opends.server.types.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.messages.LoggerMessages.*;
import static org.opends.server.messages.ConfigMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.messages.MessageHandler.getMessage;
import org.opends.server.admin.std.server.FileBasedAccessLogPublisherCfg;
import org.opends.server.admin.server.ConfigurationChangeListener;
import static org.opends.server.util.StaticUtils.getFileForPath;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import org.opends.server.util.TimeThread;
/**
 * This class provides the implementation of the access logger used by
 * the directory server.
 */
public class DirectoryAccessLogger extends AccessLogger
       implements ConfigurableComponent
public class TextAccessLogPublisher
    extends AccessLogPublisher<FileBasedAccessLogPublisherCfg>
    implements ConfigurationChangeListener<FileBasedAccessLogPublisherCfg>
{
  private static final int DEFAULT_TIME_INTERVAL = 30000;
  private static final int DEFAULT_BUFFER_SIZE = 65536;
  private boolean suppressInternalOps = true;
  private Logger accessLogger = null;
  private String changedLogFileName = null;
  private DirectoryFileHandler fileHandler = null;
  private TextWriter writer;
  // The DN of the config entry this component is associated with.
  private DN configDN;
  private FileBasedAccessLogPublisherCfg currentConfig;
  /**
   * Initializes this access logger based on the information in the provided
   * configuration entry.
   * 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  configEntry  The configuration entry that contains the information
   *                      to use to initialize this access logger.
   *
   * @throws  ConfigException  If an unrecoverable problem arises in the
   *                           process of performing the initialization.
  */
  public void initializeAccessLogger(ConfigEntry configEntry)
         throws ConfigException
   * @param writer The text writer where the message will be written to.
   * @return The instance of the text error log publisher that will print
   * all messages to standard out.
   */
  public static TextAccessLogPublisher
      getStartupTextAccessPublisher(TextWriter writer)
  {
    configDN = configEntry.getDN();
    TextAccessLogPublisher startupPublisher = new TextAccessLogPublisher();
    startupPublisher.writer = writer;
    // FIXME - read the logger name from the config
    StringConfigAttribute logFileStub =
                  new StringConfigAttribute(ATTR_LOGGER_FILE,
                  getMessage(MSGID_CONFIG_LOGGER_DESCRIPTION_CLASS_NAME),
                  true, false, true);
    StringConfigAttribute logFileNameAttr = (StringConfigAttribute)
                  configEntry.getConfigAttribute(logFileStub);
    if(logFileNameAttr == null)
    {
      int msgID = MSGID_CONFIG_LOGGER_NO_FILE_NAME;
      String message = getMessage(msgID, configEntry.getDN().toString());
      throw new ConfigException(msgID, message);
    }
    initializeAccessLogger(logFileNameAttr.activeValue(), configEntry);
    return startupPublisher;
  }
  /**
   * {@inheritDoc}
   */
  public void initializeAccessLogPublisher(
      FileBasedAccessLogPublisherCfg config)
      throws ConfigException, InitializationException
  {
    File logFile = getFileForPath(config.getLogFile());
    FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
    try
    {
      FilePermission perm =
          FilePermission.decodeUNIXMode(config.getLogFileMode());
      LogPublisherErrorHandler errorHandler =
          new LogPublisherErrorHandler(config.dn());
      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());
      // Validate retention and rotation policies.
      for(DN dn : config.getRotationPolicyDN())
      {
        RotationPolicy policy = DirectoryServer.getRotationPolicy(dn);
        if(policy != null)
        {
          writer.addRotationPolicy(policy);
        }
        else
        {
          int msgID = MSGID_CONFIG_LOGGER_INVALID_ROTATION_POLICY;
          String message = getMessage(msgID, dn.toString(),
                                      config.dn().toString());
          throw new ConfigException(msgID, message);
        }
      }
      for(DN dn: config.getRetentionPolicyDN())
      {
        RetentionPolicy policy = DirectoryServer.getRetentionPolicy(dn);
        if(policy != null)
        {
          writer.addRetentionPolicy(policy);
        }
        else
        {
          int msgID = MSGID_CONFIG_LOGGER_INVALID_RETENTION_POLICY;
          String message = getMessage(msgID, dn.toString(),
                                      config.dn().toString());
          throw new ConfigException(msgID, message);
        }
      }
      if(config.isAsynchronous())
      {
        this.writer = new AsyncronousTextWriter("Asyncronous Text Writer for " +
            config.dn().toNormalizedString(), config.getQueueSize(),
                                              config.isAutoFlush(),
                                              writer);
      }
      else
      {
        this.writer = writer;
      }
    }
    catch(DirectoryException e)
    {
      int msgID = MSGID_CONFIG_LOGGING_CANNOT_CREATE_WRITER;
      String message = getMessage(msgID, config.dn().toString(),
                                  String.valueOf(e));
      throw new InitializationException(msgID, message, e);
    }
    catch(IOException e)
    {
      int msgID = MSGID_CONFIG_LOGGING_CANNOT_CREATE_WRITER;
      String message = getMessage(msgID, config.dn().toString(),
                                  String.valueOf(e));
      throw new InitializationException(msgID, message, e);
    }
    suppressInternalOperations = config.isSuppressInternalOperations();
    currentConfig = config;
    config.addFileBasedAccessChangeListener(this);
  }
  /**
   * Closes this access logger and releases any resources it might have held.
   * {@inheritDoc}
   */
  public void closeAccessLogger()
  public boolean isConfigurationChangeAcceptable(
       FileBasedAccessLogPublisherCfg config, List<String> unacceptableReasons)
   {
     // Make sure the permission is valid.
     try
     {
       if(!currentConfig.getLogFileMode().equalsIgnoreCase(
           config.getLogFileMode()))
       {
         FilePermission.decodeUNIXMode(config.getLogFileMode());
       }
       if(!currentConfig.getLogFile().equalsIgnoreCase(config.getLogFile()))
       {
         File logFile = getFileForPath(config.getLogFile());
         if(logFile.createNewFile())
         {
           logFile.delete();
         }
       }
     }
     catch(Exception e)
     {
       int msgID = MSGID_CONFIG_LOGGING_CANNOT_CREATE_WRITER;
       String message = getMessage(msgID, config.dn().toString(),
                                    stackTraceToSingleLineString(e));
       unacceptableReasons.add(message);
       return false;
     }
     // Validate retention and rotation policies.
     for(DN dn : config.getRotationPolicyDN())
     {
       RotationPolicy policy = DirectoryServer.getRotationPolicy(dn);
       if(policy == null)
       {
         int msgID = MSGID_CONFIG_LOGGER_INVALID_ROTATION_POLICY;
         String message = getMessage(msgID, dn.toString(),
                                     config.dn().toString());
         unacceptableReasons.add(message);
         return false;
       }
     }
     for(DN dn: config.getRetentionPolicyDN())
     {
       RetentionPolicy policy = DirectoryServer.getRetentionPolicy(dn);
       if(policy == null)
       {
         int msgID = MSGID_CONFIG_LOGGER_INVALID_RETENTION_POLICY;
         String message = getMessage(msgID, dn.toString(),
                                     config.dn().toString());
         unacceptableReasons.add(message);
         return false;
       }
     }
     return true;
   }
  /**
   * {@inheritDoc}
   */
   public ConfigChangeResult applyConfigurationChange(
       FileBasedAccessLogPublisherCfg config)
   {
     // Default result code.
     ResultCode resultCode = ResultCode.SUCCESS;
     boolean adminActionRequired = false;
     ArrayList<String> messages = new ArrayList<String>();
     suppressInternalOperations = config.isSuppressInternalOperations();
     File logFile = getFileForPath(config.getLogFile());
     FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
     try
     {
       FilePermission perm =
           FilePermission.decodeUNIXMode(config.getLogFileMode());
       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.getRotationPolicyDN())
         {
           RotationPolicy policy = DirectoryServer.getRotationPolicy(dn);
           if(policy != null)
           {
             mfWriter.addRotationPolicy(policy);
           }
           else
           {
             int msgID = MSGID_CONFIG_LOGGER_INVALID_ROTATION_POLICY;
             String message = getMessage(msgID, dn.toString(),
                                         config.dn().toString());
             resultCode = DirectoryServer.getServerErrorResultCode();
             messages.add(message);
           }
         }
         for(DN dn: config.getRetentionPolicyDN())
         {
           RetentionPolicy policy = DirectoryServer.getRetentionPolicy(dn);
           if(policy != null)
           {
             mfWriter.addRetentionPolicy(policy);
           }
           else
           {
             int msgID = MSGID_CONFIG_LOGGER_INVALID_RETENTION_POLICY;
             String message = getMessage(msgID, dn.toString(),
                                         config.dn().toString());
             resultCode = DirectoryServer.getServerErrorResultCode();
             messages.add(message);
           }
         }
         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)
     {
       int msgID = MSGID_CONFIG_LOGGING_CANNOT_CREATE_WRITER;
       String message = getMessage(msgID, config.dn().toString(),
                                   stackTraceToSingleLineString(e));
       resultCode = DirectoryServer.getServerErrorResultCode();
       messages.add(message);
     }
     return new ConfigChangeResult(resultCode, adminActionRequired, messages);
   }
  /**
   * {@inheritDoc}
   */
  public void close()
  {
    fileHandler.close();
    writer.shutdown();
    if(currentConfig != null)
    {
      currentConfig.removeFileBasedAccessChangeListener(this);
    }
  }
@@ -143,12 +400,15 @@
  public void logConnect(ClientConnection clientConnection)
  {
    long connectionID = clientConnection.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("CONNECT conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" CONNECT conn=");
    buffer.append(connectionID);
    buffer.append(" from=");
    buffer.append(clientConnection.getClientAddress());
@@ -157,7 +417,7 @@
    buffer.append(" protocol=");
    buffer.append(clientConnection.getProtocol());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -177,13 +437,15 @@
                            String message)
  {
    long connectionID = clientConnection.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("DISCONNECT conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" DISCONNECT conn=");
    buffer.append(connectionID);
    buffer.append(" reason=\"");
    buffer.append(disconnectReason);
@@ -196,7 +458,7 @@
    buffer.append("\"");
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -211,14 +473,16 @@
  public void logAbandonRequest(AbandonOperation abandonOperation)
  {
    long connectionID = abandonOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("ABANDON conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" ABANDON conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(abandonOperation.getOperationID());
@@ -227,7 +491,7 @@
    buffer.append(" idToAbandon=");
    buffer.append(abandonOperation.getIDToAbandon());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
  /**
@@ -240,13 +504,15 @@
  public void logAbandonResult(AbandonOperation abandonOperation)
  {
    long connectionID = abandonOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("ABANDON conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" ABANDON conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(abandonOperation.getOperationID());
@@ -266,7 +532,7 @@
    buffer.append(" etime=");
    buffer.append(abandonOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -280,13 +546,15 @@
  public void logAddRequest(AddOperation addOperation)
  {
    long connectionID = addOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("ADD conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" ADD conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(addOperation.getOperationID());
@@ -296,7 +564,7 @@
    addOperation.getRawEntryDN().toString(buffer);
    buffer.append("\"");
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -310,13 +578,15 @@
  public void logAddResponse(AddOperation addOperation)
  {
    long connectionID = addOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("ADD conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" ADD conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(addOperation.getOperationID());
@@ -335,7 +605,7 @@
    buffer.append("\" etime=");
    buffer.append(addOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -350,13 +620,15 @@
  public void logBindRequest(BindOperation bindOperation)
  {
    long connectionID = bindOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("BIND conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" BIND conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(bindOperation.getOperationID());
@@ -382,7 +654,7 @@
    bindOperation.getRawBindDN().toString(buffer);
    buffer.append("\"");
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -396,13 +668,15 @@
  public void logBindResponse(BindOperation bindOperation)
  {
    long connectionID = bindOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("BIND conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" BIND conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(bindOperation.getOperationID());
@@ -435,7 +709,7 @@
    buffer.append("\" etime=");
    buffer.append(bindOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -449,13 +723,15 @@
  public void logCompareRequest(CompareOperation compareOperation)
  {
    long connectionID = compareOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("COMPARE conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" COMPARE conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(compareOperation.getOperationID());
@@ -466,7 +742,7 @@
    buffer.append("\" attr=");
    buffer.append(compareOperation.getAttributeType());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -480,13 +756,15 @@
  public void logCompareResponse(CompareOperation compareOperation)
  {
    long connectionID = compareOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("COMPARE conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" COMPARE conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(compareOperation.getOperationID());
@@ -505,7 +783,7 @@
    buffer.append("\" etime=");
    buffer.append(compareOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -519,13 +797,15 @@
  public void logDeleteRequest(DeleteOperation deleteOperation)
  {
    long connectionID = deleteOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("DELETE conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" DELETE conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(deleteOperation.getOperationID());
@@ -536,7 +816,7 @@
    buffer.append("\"");
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -550,13 +830,15 @@
  public void logDeleteResponse(DeleteOperation deleteOperation)
  {
    long connectionID = deleteOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("DELETE conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" DELETE conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(deleteOperation.getOperationID());
@@ -575,7 +857,7 @@
    buffer.append("\" etime=");
    buffer.append(deleteOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -590,13 +872,15 @@
  public void logExtendedRequest(ExtendedOperation extendedOperation)
  {
    long connectionID = extendedOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("EXTENDED conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" EXTENDED conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(extendedOperation.getOperationID());
@@ -606,7 +890,7 @@
    buffer.append(extendedOperation.getRequestOID());
    buffer.append("\"");
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -621,13 +905,15 @@
  public void logExtendedResponse(ExtendedOperation extendedOperation)
  {
    long connectionID = extendedOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("EXTENDED conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" EXTENDED conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(extendedOperation.getOperationID());
@@ -655,7 +941,7 @@
    buffer.append("\" etime=");
    buffer.append(extendedOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -670,13 +956,15 @@
  public void logModifyRequest(ModifyOperation modifyOperation)
  {
    long connectionID = modifyOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("MODIFY conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" MODIFY conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(modifyOperation.getOperationID());
@@ -686,7 +974,7 @@
    modifyOperation.getRawEntryDN().toString(buffer);
    buffer.append("\"");
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -701,13 +989,15 @@
  public void logModifyResponse(ModifyOperation modifyOperation)
  {
    long connectionID = modifyOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("MODIFY conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" MODIFY conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(modifyOperation.getOperationID());
@@ -726,7 +1016,7 @@
    buffer.append("\" etime=");
    buffer.append(modifyOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -741,13 +1031,15 @@
  public void logModifyDNRequest(ModifyDNOperation modifyDNOperation)
  {
    long connectionID = modifyDNOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("MODIFYDN conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" MODIFYDN conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(modifyDNOperation.getOperationID());
@@ -767,7 +1059,7 @@
      newSuperior.toString(buffer);
    }
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -783,13 +1075,15 @@
  public void logModifyDNResponse(ModifyDNOperation modifyDNOperation)
  {
    long connectionID = modifyDNOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("MODIFYDN conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" MODIFYDN conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(modifyDNOperation.getOperationID());
@@ -808,7 +1102,7 @@
    buffer.append("\" etime=");
    buffer.append(modifyDNOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -822,13 +1116,15 @@
  public void logSearchRequest(SearchOperation searchOperation)
  {
    long connectionID = searchOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("SEARCH conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" SEARCH conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(searchOperation.getOperationID());
@@ -861,7 +1157,7 @@
      buffer.append("\"");
    }
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -908,13 +1204,15 @@
  public void logSearchResultDone(SearchOperation searchOperation)
  {
    long connectionID = searchOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("SEARCH conn=");
    buffer.append("[");
    buffer.append(TimeThread.getLocalTime());
    buffer.append("]");
    buffer.append(" SEARCH conn=");
    buffer.append(connectionID);
    buffer.append(" op=");
    buffer.append(searchOperation.getOperationID());
@@ -935,7 +1233,7 @@
    buffer.append(" etime=");
    buffer.append(searchOperation.getProcessingTime());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
    writer.writeRecord(buffer.toString());
  }
@@ -950,270 +1248,22 @@
  public void logUnbind(UnbindOperation unbindOperation)
  {
    long connectionID = unbindOperation.getConnectionID();
    if(connectionID < 0 && suppressInternalOps)
    if (connectionID < 0 && suppressInternalOperations)
    {
      return;
    }
    StringBuilder buffer = new StringBuilder(50);
    buffer.append("UNBIND conn=");
    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());
    accessLogger.log(DirectoryLogLevel.INFORMATIONAL, buffer.toString());
  }
  /**
   * Indicates whether the provided object is equal to this access logger.
   *
   * @param  obj  The object for which to make the determination.
   *
   * @return  <CODE>true</CODE> if the provided object is equal
   *          to this access logger, or <CODE>false</CODE> if not.
   */
  public boolean equals(Object obj)
  {
    if(this == obj) {
      return true;
    }
    if((obj == null) || (obj.getClass() != this.getClass()))
    {
      return false;
    }
    return accessLogger.equals(obj);
  }
  /**
   * Retrieves the hash code for this access logger.
   *
   * @return  The hash code for this access logger.
   */
  public int hashCode()
  {
    return accessLogger.hashCode();
  }
  /**
   * Retrieves the DN of the configuration entry with which this component is
   * associated.
   *
   * @return  The DN of the configuration entry with which this component is
   *          associated.
   */
  public DN getConfigurableComponentEntryDN()
  {
    return configDN;
  }
  /**
   * Retrieves the set of configuration attributes that are associated with this
   * configurable component.
   *
   * @return  The set of configuration attributes that are associated with this
   *          configurable component.
   */
  public List<ConfigAttribute> getConfigurationAttributes()
  {
    // NYI
    return null;
  }
  /**
   * Indicates whether the configuration entry that will result from a proposed
   * modification is acceptable to this change listener.
   *
   * @param  configEntry         The configuration entry that will result from
   *                             the requested update.
   * @param  unacceptableReasons  A buffer to which this method can append a
   *                             human-readable message explaining why the
   *                             proposed change is not acceptable.
   *
   * @return  <CODE>true</CODE> if the proposed entry contains an acceptable
   *          configuration, or <CODE>false</CODE> if it does not.
   */
  public boolean hasAcceptableConfiguration(ConfigEntry configEntry,
                                          List<String> unacceptableReasons)
  {
    try
    {
      StringConfigAttribute logFileStub =
      new StringConfigAttribute(ATTR_LOGGER_FILE,
      getMessage(MSGID_CONFIG_LOGGER_DESCRIPTION_CLASS_NAME),
      true, false, true);
      StringConfigAttribute logFileNameAttr = (StringConfigAttribute)
          configEntry.getConfigAttribute(logFileStub);
      if(logFileNameAttr == null)
      {
        int msgID = MSGID_CONFIG_LOGGER_NO_FILE_NAME;
        String message = getMessage(msgID, configEntry.getDN().toString());
        unacceptableReasons.add(message);
        return false;
      }
      changedLogFileName = logFileNameAttr.pendingValue();
    } catch (ConfigException ce)
    {
      int msgID   = MSGID_CONFIG_LOGGER_INVALID_ACCESS_LOGGER_CLASS;
      String message = getMessage(msgID, this.getClass().getName(),
          configEntry.getDN().toString(),
          String.valueOf(ce));
      unacceptableReasons.add(message);
      return false;
    }
    return true;
  }
  /**
   * Attempts to apply a new configuration to this Directory Server component
   * based on the provided changed entry.
   *
   * @param  configEntry      The configuration entry that containing the
   *                          updated configuration for this component.
   * @param  detailedResults  Indicates whether to provide detailed information
   *                          about any actions performed.
   *
   * @return  Information about the result of processing the configuration
   *          change.
   */
  public ConfigChangeResult applyNewConfiguration(ConfigEntry configEntry,
                  boolean detailedResults)
  {
    fileHandler.close();
    // reinitialize the logger.
    try
    {
      initializeAccessLogger(changedLogFileName, configEntry);
    } catch(ConfigException ce)
    {
      // TODO - log the change failure.
      return new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
                                    false);
    }
    return new ConfigChangeResult(ResultCode.SUCCESS, false);
  }
  /**
   * Initialize the JDK logger an associate a file handler with the
   * specified file name with it.
   *
   * @param logFileName The name of the log file to write to.
   * @param configEntry The configuration entry with the information to use to
   *                    initialize this logger.
   *
   * @throws ConfigException   If an unrecoverable problem arises in the
   *                           process of performing the initialization.
   */
  private void initializeAccessLogger(String logFileName,
    ConfigEntry configEntry) throws ConfigException
  {
    accessLogger =
      Logger.getLogger("org.opends.server.loggers.DirectoryAccessLogger");
    accessLogger.setLevel(Level.ALL);
    File logFile = new File(logFileName);
    if(!logFile.isAbsolute())
    {
      logFile = new File (DirectoryServer.getServerRoot() + File.separator +
          logFileName);
    }
    BooleanConfigAttribute enabledAttr;
    try
    {
      BooleanConfigAttribute enabledStub =
           new BooleanConfigAttribute(ATTR_LOGGER_SUPPRESS_INTERNAL_OPERATIONS,
                   getMessage(MSGID_CONFIG_LOGGER_SUPPRESS_INTERNAL_OPERATIONS),
                               false);
      enabledAttr = (BooleanConfigAttribute)
                    configEntry.getConfigAttribute(enabledStub);
      if (enabledAttr != null)
      {
        suppressInternalOps = enabledAttr.pendingValue();
      }
    }
    catch (Exception e)
    {
      int msgID = MSGID_CONFIG_LOGGER_INVALID_SUPPRESS_INT_OPERATION_VALUE;
      String message = getMessage(msgID, configEntry.getDN().toString(),
                                  String.valueOf(e));
      throw new ConfigException(msgID, message);
    }
    try
    {
      int bufferSize = RotationConfigUtil.getIntegerAttribute(configEntry,
                        ATTR_LOGGER_BUFFER_SIZE, MSGID_LOGGER_BUFFER_SIZE);
      if(bufferSize == -1)
      {
        bufferSize = DEFAULT_BUFFER_SIZE;
      }
      CopyOnWriteArrayList<RotationPolicy> rp =
        RotationConfigUtil.getRotationPolicies(configEntry);
      fileHandler = new DirectoryFileHandler(configEntry,
                logFile.getAbsolutePath(),
                bufferSize);
      fileHandler.setFormatter(new DirectoryFileFormatter(false));
      accessLogger.addHandler(fileHandler);
      if(rp != null)
      {
        ArrayList<ActionType> actions =
          RotationConfigUtil.getPostRotationActions(configEntry);
        fileHandler.setPostRotationActions(actions);
        for(RotationPolicy rotationPolicy : rp)
        {
          if(rotationPolicy instanceof SizeBasedRotationPolicy)
          {
            long fileSize =
              ((SizeBasedRotationPolicy) rotationPolicy).getMaxFileSize();
            fileHandler.setFileSize(fileSize);
            rp.remove(rotationPolicy);
          }
        }
      }
      CopyOnWriteArrayList<RetentionPolicy> retentionPolicies =
        RotationConfigUtil.getRetentionPolicies(configEntry);
      int threadTimeInterval = RotationConfigUtil.getIntegerAttribute(
        configEntry, ATTR_LOGGER_THREAD_INTERVAL,
        MSGID_LOGGER_THREAD_INTERVAL);
      if(threadTimeInterval == -1)
      {
        threadTimeInterval = DEFAULT_TIME_INTERVAL;
      }
      LoggerThread lt = new LoggerThread("AccessLogger Thread",
            threadTimeInterval, fileHandler, rp,
                              retentionPolicies);
      lt.start();
    } catch(IOException ioe) {
      int    msgID   = MSGID_LOG_ACCESS_CANNOT_ADD_FILE_HANDLER;
      String message = getMessage(msgID, String.valueOf(ioe));
      throw new ConfigException(msgID, message, ioe);
    }
    writer.writeRecord(buffer.toString());
  }
}