From d57e8fd5ca53257eab611c2a592de8b57d086158 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 27 Jul 2011 16:31:30 +0000
Subject: [PATCH] Fix OPENDJ-245: Improve APIs for adding additional access log items to operations

---
 opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java                       |    6 
 opends/src/server/org/opends/server/types/operation/PreOperationOperation.java                    |   63 +--
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/IsolationTest.java |    8 
 opends/src/server/org/opends/server/types/AbstractOperation.java                                  |   70 +---
 opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java             |   26 
 opends/src/server/org/opends/server/types/operation/PreParseOperation.java                        |   38 -
 opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java                 |   15 
 opends/src/server/org/opends/server/types/AdditionalLogItem.java                                  |  245 +++++++++++++++
 opends/src/server/org/opends/server/types/operation/InProgressOperation.java                      |   66 +--
 opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java               |   12 
 opends/tests/unit-tests-testng/src/server/org/opends/server/types/AdditionalLogItemTest.java      |   96 ++++++
 opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java                           |   95 +----
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java  |    6 
 opends/src/server/org/opends/server/backends/jeb/EntryContainer.java                              |    5 
 opends/src/server/org/opends/server/types/operation/PostOperationOperation.java                   |   66 +--
 opends/src/server/org/opends/server/core/OperationWrapper.java                                    |   41 +-
 opends/src/server/org/opends/server/types/operation/PostResponseOperation.java                    |   26 
 opends/src/server/org/opends/server/types/Operation.java                                          |   36 -
 opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java                 |   39 --
 19 files changed, 560 insertions(+), 399 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 5bd4da4..e153018 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -2057,8 +2057,9 @@
 
       if(isSubtreeDelete)
       {
-        deleteOperation.appendAdditionalLogMessage(
-            NOTE_JEB_DELETED_ENTRY_COUNT.get(subordinateEntriesDeleted + 1));
+        deleteOperation.addAdditionalLogItem(AdditionalLogItem
+            .unquotedKeyValue(getClass(), "deletedEntries",
+                subordinateEntriesDeleted + 1));
       }
     }
     catch (DatabaseException databaseException)
diff --git a/opends/src/server/org/opends/server/core/OperationWrapper.java b/opends/src/server/org/opends/server/core/OperationWrapper.java
index f7691a4..d385c16 100644
--- a/opends/src/server/org/opends/server/core/OperationWrapper.java
+++ b/opends/src/server/org/opends/server/core/OperationWrapper.java
@@ -77,14 +77,6 @@
   /**
    * {@inheritDoc}
    */
-  public void appendAdditionalLogMessage(Message message)
-  {
-    operation.appendAdditionalLogMessage(message);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
   public void appendErrorMessage(Message message)
   {
     operation.appendErrorMessage(message);
@@ -130,14 +122,6 @@
   /**
    * {@inheritDoc}
    */
-  public MessageBuilder getAdditionalLogMessage()
-  {
-    return operation.getAdditionalLogMessage();
-  }
-
-  /**
-   * {@inheritDoc}
-   */
   public Object getAttachment(String name)
   {
     return operation.getAttachment(name);
@@ -387,14 +371,6 @@
   /**
    * {@inheritDoc}
    */
-  public void setAdditionalLogMessage(MessageBuilder additionalLogMessage)
-  {
-    operation.setAdditionalLogMessage(additionalLogMessage);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
   public Object setAttachment(String name, Object value)
   {
     return operation.setAttachment(name, value);
@@ -539,5 +515,22 @@
   {
     operation.registerPostResponseCallback(callback);
   }
+
+  /**
+   * {@inheritDoc}
+   */
+  public List<AdditionalLogItem> getAdditionalLogItems()
+  {
+    return operation.getAdditionalLogItems();
+  }
+
+  /**
+   *{@inheritDoc}
+   */
+  public void addAdditionalLogItem(AdditionalLogItem item)
+  {
+    operation.addAdditionalLogItem(item);
+  }
+
 }
 
diff --git a/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java b/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
index b83173d..cb5b6ae 100644
--- a/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
+++ b/opends/src/server/org/opends/server/extensions/AnonymousSASLMechanismHandler.java
@@ -23,21 +23,18 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.extensions;
 
 
 
-import org.opends.messages.MessageBuilder;
 import org.opends.server.admin.std.server.AnonymousSASLMechanismHandlerCfg;
 import org.opends.server.api.SASLMechanismHandler;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.BindOperation;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.types.AuthenticationInfo;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.InitializationException;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import static org.opends.messages.ExtensionMessages.*;
 import static org.opends.server.loggers.ErrorLogger.*;
@@ -111,12 +108,8 @@
       String credString = saslCredentials.toString();
       if (credString.length() > 0)
       {
-        MessageBuilder mb = new MessageBuilder();
-        mb.append("trace='");
-        mb.append(credString);
-        mb.append("'");
-        bindOperation.appendAdditionalLogMessage(mb.toMessage());
-
+        bindOperation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(
+            getClass(), "trace", credString));
         logError(INFO_SASLANONYMOUS_TRACE.
             get(bindOperation.getConnectionID(), bindOperation.getOperationID(),
                 credString));
diff --git a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
index c80f58d..f3f4534 100644
--- a/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/PasswordModifyExtendedOperation.java
@@ -639,9 +639,9 @@
             (! operation.getClientConnection().isSecure()))
         {
           operation.setResultCode(ResultCode.CONFIDENTIALITY_REQUIRED);
-
-          operation.appendAdditionalLogMessage(
-                  ERR_EXTOP_PASSMOD_SECURE_AUTH_REQUIRED.get());
+          operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(
+              getClass(), "additionalInfo",
+              ERR_EXTOP_PASSMOD_SECURE_AUTH_REQUIRED.get()));
           return;
         }
 
@@ -652,9 +652,9 @@
         else
         {
           operation.setResultCode(ResultCode.INVALID_CREDENTIALS);
-
-          operation.appendAdditionalLogMessage(
-                  ERR_EXTOP_PASSMOD_INVALID_OLD_PASSWORD.get());
+          operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(
+              getClass(), "additionalInfo",
+              ERR_EXTOP_PASSMOD_INVALID_OLD_PASSWORD.get()));
 
           pwPolicyState.updateAuthFailureTimes();
           List<Modification> mods = pwPolicyState.getModifications();
diff --git a/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java b/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java
index 7a1ddc0..1e1053f 100644
--- a/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java
+++ b/opends/src/server/org/opends/server/extensions/WhoAmIExtendedOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.extensions;
 
@@ -31,7 +32,6 @@
 import java.util.HashSet;
 import java.util.Set;
 
-import org.opends.messages.Message;
 import org.opends.server.admin.std.server.WhoAmIExtendedOperationHandlerCfg;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.ExtendedOperationHandler;
@@ -200,8 +200,8 @@
     }
 
     operation.setResponseValue(ByteString.valueOf(authzID));
-    operation.appendAdditionalLogMessage(
-            Message.raw("authzID=\"" + authzID + "\""));
+    operation.addAdditionalLogItem(AdditionalLogItem.quotedKeyValue(
+        getClass(), "authzID", authzID));
     operation.setResultCode(ResultCode.SUCCESS);
   }
 
diff --git a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
index 6d75514..7113b30 100644
--- a/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -60,16 +60,7 @@
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.core.SearchOperation;
 import org.opends.server.core.UnbindOperation;
-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.types.*;
 import org.opends.server.util.TimeThread;
 
 
@@ -485,13 +476,7 @@
       buffer.append('\"');
     }
 
-    msg = abandonOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(abandonOperation, buffer);
 
     buffer.append(" etime=");
     buffer.append(abandonOperation.getProcessingTime());
@@ -571,13 +556,7 @@
       buffer.append('\"');
     }
 
-    msg = addOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(addOperation, buffer);
 
     DN proxiedAuthDN = addOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
@@ -703,13 +682,7 @@
       buffer.append('\"');
     }
 
-    msg = bindOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(bindOperation, buffer);
 
     if (bindOperation.getResultCode() == ResultCode.SUCCESS)
     {
@@ -825,13 +798,7 @@
       buffer.append('\"');
     }
 
-    msg = compareOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(compareOperation, buffer);
 
     DN proxiedAuthDN = compareOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
@@ -974,13 +941,7 @@
       buffer.append('\"');
     }
 
-    msg = deleteOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(deleteOperation, buffer);
 
     DN proxiedAuthDN = deleteOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
@@ -1166,13 +1127,7 @@
       buffer.append('\"');
     }
 
-    msg = extendedOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(extendedOperation, buffer);
 
     buffer.append(" etime=");
     long etime = extendedOperation.getProcessingNanoTime();
@@ -1270,13 +1225,7 @@
       buffer.append('\"');
     }
 
-    msg = modifyDNOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(modifyDNOperation, buffer);
 
     DN proxiedAuthDN = modifyDNOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
@@ -1369,13 +1318,7 @@
       buffer.append('\"');
     }
 
-    msg = modifyOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(modifyOperation, buffer);
 
     DN proxiedAuthDN = modifyOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
@@ -1494,13 +1437,7 @@
     buffer.append(" nentries=");
     buffer.append(searchOperation.getEntriesSent());
 
-    msg = searchOperation.getAdditionalLogMessage();
-    if ((msg != null) && (msg.length() > 0))
-    {
-      buffer.append(" additionalInfo=\"");
-      buffer.append(msg);
-      buffer.append('\"');
-    }
+    logAdditionalLogItems(searchOperation, buffer);
 
     DN proxiedAuthDN = searchOperation.getProxiedAuthorizationDN();
     if (proxiedAuthDN != null)
@@ -1596,6 +1533,18 @@
 
 
 
+  // Appends additional log items to the provided builder.
+  private void logAdditionalLogItems(Operation operation, StringBuilder builder)
+  {
+    for (AdditionalLogItem item : operation.getAdditionalLogItems())
+    {
+      builder.append(' ');
+      item.toString(builder);
+    }
+  }
+
+
+
   // Writes an intermediate message to the log.
   private void logIntermediateMessage(Operation operation, String opType,
       String category, Map<String, String> content)
diff --git a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 0b72925..9ac8831 100644
--- a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -108,39 +108,7 @@
 import org.opends.server.replication.service.ReplicationDomain;
 import org.opends.server.replication.service.ReplicationMonitor;
 import org.opends.server.tasks.TaskUtils;
-import org.opends.server.types.AbstractOperation;
-import org.opends.server.types.Attribute;
-import org.opends.server.types.AttributeBuilder;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
-import org.opends.server.types.AttributeValues;
-import org.opends.server.types.Attributes;
-import org.opends.server.types.ByteString;
-import org.opends.server.types.ConfigChangeResult;
-import org.opends.server.types.Control;
-import org.opends.server.types.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.DereferencePolicy;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.Entry;
-import org.opends.server.types.ExistingFileBehavior;
-import org.opends.server.types.LDAPException;
-import org.opends.server.types.LDIFExportConfig;
-import org.opends.server.types.LDIFImportConfig;
-import org.opends.server.types.Modification;
-import org.opends.server.types.ModificationType;
-import org.opends.server.types.ObjectClass;
-import org.opends.server.types.Operation;
-import org.opends.server.types.OperationType;
-import org.opends.server.types.RDN;
-import org.opends.server.types.RawModification;
-import org.opends.server.types.ResultCode;
-import org.opends.server.types.Schema;
-import org.opends.server.types.SearchFilter;
-import org.opends.server.types.SearchResultEntry;
-import org.opends.server.types.SearchResultReference;
-import org.opends.server.types.SearchScope;
-import org.opends.server.types.SynchronizationProviderResult;
+import org.opends.server.types.*;
 import org.opends.server.types.operation.PluginOperation;
 import org.opends.server.types.operation.PostOperationAddOperation;
 import org.opends.server.types.operation.PostOperationDeleteOperation;
@@ -2324,9 +2292,8 @@
     ChangeNumber curChangeNumber = OperationContext.getChangeNumber(op);
     if ((curChangeNumber != null) && (logChangeNumber))
     {
-      Message message =
-        Message.raw("replicationCN:%s", curChangeNumber.toString());
-      op.appendAdditionalLogMessage(message);
+      op.addAdditionalLogItem(AdditionalLogItem.unquotedKeyValue(getClass(),
+          "replicationCN", curChangeNumber));
     }
 
     if ((result == ResultCode.SUCCESS) && (!op.isSynchronizationOperation()))
diff --git a/opends/src/server/org/opends/server/types/AbstractOperation.java b/opends/src/server/org/opends/server/types/AbstractOperation.java
index a79b440..b02e4f7 100644
--- a/opends/src/server/org/opends/server/types/AbstractOperation.java
+++ b/opends/src/server/org/opends/server/types/AbstractOperation.java
@@ -32,14 +32,12 @@
 
 import static org.opends.server.core.CoreConstants.*;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+
 import org.opends.server.api.ClientConnection;
 import org.opends.server.types.operation.PostResponseOperation;
 import org.opends.server.types.operation.PreParseOperation;
+import org.opends.server.util.Validator;
 import org.opends.server.core.DirectoryServer;
 
 import static org.opends.server.loggers.debug.
@@ -147,7 +145,7 @@
 
   // Additional information that should be included in the log but
   // not sent to the client.
-  private MessageBuilder additionalLogMessage;
+  private List<AdditionalLogItem> additionalLogItems;
 
   // The error message for this operation that should be included in
   // the log and in the response to the client.
@@ -207,7 +205,7 @@
     }
 
     resultCode                 = ResultCode.UNDEFINED;
-    additionalLogMessage       = null;
+    additionalLogItems         = null;
     errorMessage               = new MessageBuilder();
     attachments                = new HashMap<String,Object>();
     matchedDN                  = null;
@@ -565,64 +563,33 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by
-   * pre-parse, pre-operation, and post-operation plugins, but not by
-   * post-response plugins.
-   *
-   * @return  The additional log message for this operation.
+   * {@inheritDoc}
    */
-  public final MessageBuilder getAdditionalLogMessage()
+  public List<AdditionalLogItem> getAdditionalLogItems()
   {
-    return additionalLogMessage;
-  }
-
-
-
-  /**
-   * Specifies the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  This method may not be called by post-response
-   * plugins.
-   *
-   * @param  additionalLogMessage  The additional log message for this
-   *                               operation.
-   */
-  public final void setAdditionalLogMessage(
-                         MessageBuilder additionalLogMessage)
-  {
-    if (additionalLogMessage == null)
+    if (additionalLogItems == null)
     {
-      this.additionalLogMessage = new MessageBuilder();
+      return Collections.emptyList();
     }
     else
     {
-      this.additionalLogMessage = additionalLogMessage;
+      return Collections.unmodifiableList(additionalLogItems);
     }
   }
 
 
 
   /**
-   * Appends the provided message to the additional log information
-   * for this operation.  This method may not be called by
-   * post-response plugins.
-   *
-   * @param  message  The message that should be appended to the
-   *                  additional log information for this operation.
+   * {@inheritDoc}
    */
-  public final void appendAdditionalLogMessage(Message message)
+  public void addAdditionalLogItem(AdditionalLogItem item)
   {
-    if (additionalLogMessage == null)
+    Validator.ensureNotNull(item);
+    if (additionalLogItems == null)
     {
-      additionalLogMessage = new MessageBuilder(message);
+      additionalLogItems = new LinkedList<AdditionalLogItem>();
     }
-    else
-    {
-      additionalLogMessage.append(" ");
-      additionalLogMessage.append(message);
-    }
+    additionalLogItems.add(item);
   }
 
 
@@ -630,9 +597,8 @@
   /**
    * Retrieves the matched DN for this operation.
    *
-   * @return  The matched DN for this operation, or {@code null} if
-   *          the operation has not yet completed or does not have a
-   *          matched DN.
+   * @return The matched DN for this operation, or {@code null} if the operation
+   *         has not yet completed or does not have a matched DN.
    */
   public final DN getMatchedDN()
   {
diff --git a/opends/src/server/org/opends/server/types/AdditionalLogItem.java b/opends/src/server/org/opends/server/types/AdditionalLogItem.java
new file mode 100644
index 0000000..5390f25
--- /dev/null
+++ b/opends/src/server/org/opends/server/types/AdditionalLogItem.java
@@ -0,0 +1,245 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2011 ForgeRock AS
+ */
+package org.opends.server.types;
+
+
+
+import org.opends.server.util.Validator;
+
+
+
+/**
+ * An additional log item for an operation which may be processed in the access
+ * log.
+ * <p>
+ * Log items comprise of a source class, a key, and an optional value. If no
+ * value is present then only the key will be displayed in the log, otherwise
+ * both the key and value will usually be displayed using the format
+ * {@code key=value}. Log item values are {@code Object} instances whose string
+ * representation will be derived using the object's {@code toString()} method.
+ * <p>
+ * Log implementations may use the source class and/or key in order to filter
+ * out unwanted log items.
+ */
+public final class AdditionalLogItem
+{
+  /**
+   * Creates a new additional log item using the provided source and key, but no
+   * value.
+   *
+   * @param source
+   *          The class which generated the additional log item.
+   * @param key
+   *          The log item key.
+   * @return The new additional log item.
+   */
+  public static AdditionalLogItem keyOnly(final Class<?> source,
+      final String key)
+  {
+    Validator.ensureNotNull(source, key);
+    return new AdditionalLogItem(source, key, null, false);
+  }
+
+
+
+  /**
+   * Creates a new additional log item using the provided source, key, and
+   * value. The value will be surrounded by quotes when serialized as a string.
+   *
+   * @param source
+   *          The class which generated the additional log item.
+   * @param key
+   *          The log item key.
+   * @param value
+   *          The log item value.
+   * @return The new additional log item.
+   */
+  public static AdditionalLogItem quotedKeyValue(final Class<?> source,
+      final String key, final Object value)
+  {
+    Validator.ensureNotNull(source, key, value);
+    return new AdditionalLogItem(source, key, value, true);
+  }
+
+
+
+  /**
+   * Creates a new additional log item using the provided source, key, and
+   * value. The value will not be surrounded by quotes when serialized as a
+   * string.
+   *
+   * @param source
+   *          The class which generated the additional log item.
+   * @param key
+   *          The log item key.
+   * @param value
+   *          The log item value.
+   * @return The new additional log item.
+   */
+  public static AdditionalLogItem unquotedKeyValue(final Class<?> source,
+      final String key, final Object value)
+  {
+    Validator.ensureNotNull(source, key, value);
+    return new AdditionalLogItem(source, key, value, false);
+  }
+
+
+
+  private final Class<?> source;
+
+  private final String key;
+
+  private final Object value;
+
+  private final boolean isQuoted;
+
+
+
+  /**
+   * Creates a new additional log item.
+   *
+   * @param source
+   *          The class which generated the additional log item.
+   * @param key
+   *          The log item key.
+   * @param value
+   *          The log item value.
+   * @param isQuoted
+   *          {@code true} if this item's value should be surrounded by quotes
+   *          during serialization.
+   */
+  private AdditionalLogItem(final Class<?> source, final String key,
+      final Object value, final boolean isQuoted)
+  {
+    this.source = source;
+    this.key = key;
+    this.value = value;
+    this.isQuoted = isQuoted;
+  }
+
+
+
+  /**
+   * Returns the log item key.
+   *
+   * @return The log item key.
+   */
+  public String getKey()
+  {
+    return key;
+  }
+
+
+
+  /**
+   * Returns the class which generated the additional log item.
+   *
+   * @return The class which generated the additional log item.
+   */
+  public Class<?> getSource()
+  {
+    return source;
+  }
+
+
+
+  /**
+   * Returns the log item value, or {@code null} if this log item does not have
+   * a value.
+   *
+   * @return The log item value, or {@code null} if this log item does not have
+   *         a value.
+   */
+  public Object getValue()
+  {
+    return value;
+  }
+
+
+
+  /**
+   * Returns {@code true} if this item's value should be surrounded by quotes
+   * during serialization.
+   *
+   * @return {@code true} if this item's value should be surrounded by quotes
+   *         during serialization.
+   */
+  public boolean isQuoted()
+  {
+    return isQuoted;
+  }
+
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String toString()
+  {
+    if (value == null)
+    {
+      return key;
+    }
+    else
+    {
+      final StringBuilder builder = new StringBuilder(key.length() + 16);
+      toString(builder);
+      return builder.toString();
+    }
+  }
+
+
+
+  /**
+   * Appends the string representation of this additional log item to the
+   * provided string builder.
+   *
+   * @param builder
+   *          The string builder.
+   * @return A reference to the updated string builder.
+   */
+  public StringBuilder toString(final StringBuilder builder)
+  {
+    builder.append(key);
+    if (value != null)
+    {
+      builder.append('=');
+      if (isQuoted)
+      {
+        builder.append('\'');
+      }
+      builder.append(value.toString());
+      if (isQuoted)
+      {
+        builder.append('\'');
+      }
+    }
+    return builder;
+  }
+
+}
diff --git a/opends/src/server/org/opends/server/types/Operation.java b/opends/src/server/org/opends/server/types/Operation.java
index 301379b..da360f4 100644
--- a/opends/src/server/org/opends/server/types/Operation.java
+++ b/opends/src/server/org/opends/server/types/Operation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types;
 import org.opends.messages.Message;
@@ -278,35 +279,24 @@
   public abstract void appendErrorMessage(Message message);
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by
-   * pre-parse, pre-operation, and post-operation plugins, but not by
-   * post-response plugins.
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
    *
-   * @return  The additional log message for this operation.
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
    */
-  public abstract MessageBuilder getAdditionalLogMessage();
+  public abstract List<AdditionalLogItem> getAdditionalLogItems();
 
   /**
-   * Specifies the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  This method may not be called by post-response
-   * plugins.
+   * Adds an additional log item to this operation, which should be written to
+   * the log but not included in the response to the client. This method may not
+   * be called by post-response plugins.
    *
-   * @param  additionalLogMessage  The additional log message for this
+   * @param item
+   *          The additional log item for this operation.
    */
-  public abstract void setAdditionalLogMessage(
-      MessageBuilder additionalLogMessage);
-
-  /**
-   * Appends the provided message to the additional log information
-   * for this operation.  This method may not be called by
-   * post-response plugins.
-   *
-   * @param  message  The message that should be appended to the
-   */
-  public abstract void appendAdditionalLogMessage(Message message);
+  public abstract void addAdditionalLogItem(AdditionalLogItem item);
 
   /**
    * Retrieves the matched DN for this operation.
diff --git a/opends/src/server/org/opends/server/types/operation/InProgressOperation.java b/opends/src/server/org/opends/server/types/operation/InProgressOperation.java
index 6f6ff3b..240f422 100644
--- a/opends/src/server/org/opends/server/types/operation/InProgressOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/InProgressOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types.operation;
 import org.opends.messages.Message;
@@ -31,10 +32,7 @@
 
 import java.util.List;
 
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import org.opends.messages.MessageBuilder;
 
@@ -128,42 +126,6 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by the
-   * caller.
-   *
-   * @return  The additional log message for this operation.
-   */
-  public MessageBuilder getAdditionalLogMessage();
-
-
-
-  /**
-   * Specifies the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.
-   *
-   * @param  additionalLogMessage  The additional log message for this
-   *                               operation.
-   */
-  public void setAdditionalLogMessage(
-                   MessageBuilder additionalLogMessage);
-
-
-
-  /**
-   * Appends the provided message to the additional log information
-   * for this operation.
-   *
-   * @param  message  The message that should be appended to the
-   *                  additional log information for this operation.
-   */
-  public void appendAdditionalLogMessage(Message message);
-
-
-
-  /**
    * Retrieves the matched DN for this operation.
    *
    * @return  The matched DN for this operation, or <CODE>null</CODE>
@@ -230,5 +192,29 @@
    * @return  The authorization DN for this operation.
    */
   public DN getAuthorizationDN();
+
+
+
+  /**
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
+   *
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
+   */
+  public List<AdditionalLogItem> getAdditionalLogItems();
+
+
+
+  /**
+   * Adds an additional log item to this operation, which should be written to
+   * the log but not included in the response to the client. This method may not
+   * be called by post-response plugins.
+   *
+   * @param item
+   *          The additional log item for this operation.
+   */
+  public void addAdditionalLogItem(AdditionalLogItem item);
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostOperationOperation.java b/opends/src/server/org/opends/server/types/operation/PostOperationOperation.java
index fd8b33d..026b443 100644
--- a/opends/src/server/org/opends/server/types/operation/PostOperationOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostOperationOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types.operation;
 import org.opends.messages.Message;
@@ -31,10 +32,7 @@
 
 import java.util.List;
 
-import org.opends.server.types.Control;
-import org.opends.server.types.DirectoryException;
-import org.opends.server.types.DN;
-import org.opends.server.types.ResultCode;
+import org.opends.server.types.*;
 
 import org.opends.messages.MessageBuilder;
 
@@ -126,42 +124,6 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by the
-   * caller.
-   *
-   * @return  The additional log message for this operation.
-   */
-  public MessageBuilder getAdditionalLogMessage();
-
-
-
-  /**
-   * Specifies the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.
-   *
-   * @param  additionalLogMessage  The additional log message for this
-   *                               operation.
-   */
-  public void setAdditionalLogMessage(
-                   MessageBuilder additionalLogMessage);
-
-
-
-  /**
-   * Appends the provided message to the additional log information
-   * for this operation.
-   *
-   * @param  message  The message that should be appended to the
-   *                  additional log information for this operation.
-   */
-  public void appendAdditionalLogMessage(Message message);
-
-
-
-  /**
    * Retrieves the matched DN for this operation.
    *
    * @return  The matched DN for this operation, or <CODE>null</CODE>
@@ -228,5 +190,29 @@
    * @return  The authorization DN for this operation.
    */
   public DN getAuthorizationDN();
+
+
+
+  /**
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
+   *
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
+   */
+  public List<AdditionalLogItem> getAdditionalLogItems();
+
+
+
+  /**
+   * Adds an additional log item to this operation, which should be written to
+   * the log but not included in the response to the client. This method may not
+   * be called by post-response plugins.
+   *
+   * @param item
+   *          The additional log item for this operation.
+   */
+  public void addAdditionalLogItem(AdditionalLogItem item);
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostResponseOperation.java b/opends/src/server/org/opends/server/types/operation/PostResponseOperation.java
index 47fbdc4..a70f088 100644
--- a/opends/src/server/org/opends/server/types/operation/PostResponseOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostResponseOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types.operation;
 import org.opends.messages.MessageBuilder;
@@ -30,6 +31,7 @@
 
 import java.util.List;
 
+import org.opends.server.types.AdditionalLogItem;
 import org.opends.server.types.DN;
 import org.opends.server.types.ResultCode;
 
@@ -71,18 +73,6 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by the
-   * caller.
-   *
-   * @return  The additional log message for this operation.
-   */
-  public MessageBuilder getAdditionalLogMessage();
-
-
-
-  /**
    * Retrieves the matched DN for this operation.
    *
    * @return  The matched DN for this operation, or <CODE>null</CODE>
@@ -139,5 +129,17 @@
    *          processing this operation.
    */
   public long getProcessingTime();
+
+
+
+  /**
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
+   *
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
+   */
+  public List<AdditionalLogItem> getAdditionalLogItems();
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java b/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java
index f7e974d..929c584 100644
--- a/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PostSynchronizationOperation.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types.operation;
 import org.opends.messages.MessageBuilder;
@@ -30,6 +31,7 @@
 
 import java.util.List;
 
+import org.opends.server.types.AdditionalLogItem;
 import org.opends.server.types.DN;
 import org.opends.server.types.ResultCode;
 
@@ -72,18 +74,6 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by the
-   * caller.
-   *
-   * @return  The additional log message for this operation.
-   */
-  public MessageBuilder getAdditionalLogMessage();
-
-
-
-  /**
    * Retrieves the matched DN for this operation.
    *
    * @return  The matched DN for this operation, or <CODE>null</CODE>
@@ -140,5 +130,17 @@
    *          processing this operation.
    */
   public long getProcessingTime();
+
+
+
+  /**
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
+   *
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
+   */
+  public List<AdditionalLogItem> getAdditionalLogItems();
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PreOperationOperation.java b/opends/src/server/org/opends/server/types/operation/PreOperationOperation.java
index fcc65e7..0238c37 100644
--- a/opends/src/server/org/opends/server/types/operation/PreOperationOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreOperationOperation.java
@@ -23,11 +23,15 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types.operation;
+import java.util.List;
+
 import org.opends.messages.Message;
 
 
+import org.opends.server.types.AdditionalLogItem;
 import org.opends.server.types.Control;
 import org.opends.server.types.DN;
 
@@ -102,41 +106,6 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by the
-   * caller.
-   *
-   * @return  The additional log message for this operation.
-   */
-  public MessageBuilder getAdditionalLogMessage();
-
-
-
-  /**
-   * Specifies the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.
-   *
-   * @param  additionalLogMessage  The additional log message for this
-   */
-  public void setAdditionalLogMessage(
-                   MessageBuilder additionalLogMessage);
-
-
-
-  /**
-   * Appends the provided message to the additional log information
-   * for this operation.
-   *
-   * @param  message  The message that should be appended to the
-   *                  additional log information for this operation.
-   */
-  public void appendAdditionalLogMessage(Message message);
-
-
-
-  /**
    * Retrieves the authorization DN for this operation.  In many
    * cases, it will be the same as the DN of the authenticated user
    * for the underlying connection, or the null DN if no
@@ -148,5 +117,29 @@
    * @return  The authorization DN for this operation.
    */
   public DN getAuthorizationDN();
+
+
+
+  /**
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
+   *
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
+   */
+  public List<AdditionalLogItem> getAdditionalLogItems();
+
+
+
+  /**
+   * Adds an additional log item to this operation, which should be written to
+   * the log but not included in the response to the client. This method may not
+   * be called by post-response plugins.
+   *
+   * @param item
+   *          The additional log item for this operation.
+   */
+  public void addAdditionalLogItem(AdditionalLogItem item);
 }
 
diff --git a/opends/src/server/org/opends/server/types/operation/PreParseOperation.java b/opends/src/server/org/opends/server/types/operation/PreParseOperation.java
index 63a1215..fc80a44 100644
--- a/opends/src/server/org/opends/server/types/operation/PreParseOperation.java
+++ b/opends/src/server/org/opends/server/types/operation/PreParseOperation.java
@@ -23,8 +23,11 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Portions copyright 2011 ForgeRock AS.
  */
 package org.opends.server.types.operation;
+import java.util.List;
+
 import org.opends.messages.Message;
 
 
@@ -124,36 +127,25 @@
 
 
   /**
-   * Retrieves the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.  The contents of this buffer may be altered by the
-   * caller.
+   * Returns an unmodifiable list containing the additional log items for this
+   * operation, which should be written to the log but not included in the
+   * response to the client.
    *
-   * @return  The additional log message for this operation.
+   * @return An unmodifiable list containing the additional log items for this
+   *         operation.
    */
-  public MessageBuilder getAdditionalLogMessage();
+  public List<AdditionalLogItem> getAdditionalLogItems();
 
 
 
   /**
-   * Specifies the additional log message for this operation, which
-   * should be written to the log but not included in the response to
-   * the client.
+   * Adds an additional log item to this operation, which should be written to
+   * the log but not included in the response to the client. This method may not
+   * be called by post-response plugins.
    *
-   * @param  additionalLogMessage  The additional log message for this
+   * @param item
+   *          The additional log item for this operation.
    */
-  public void setAdditionalLogMessage(
-                   MessageBuilder additionalLogMessage);
-
-
-
-  /**
-   * Appends the provided message to the additional log information
-   * for this operation.
-   *
-   * @param  message  The message that should be appended to the
-   *                  additional log information for this operation.
-   */
-  public void appendAdditionalLogMessage(Message message);
+  public void addAdditionalLogItem(AdditionalLogItem item);
 }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
index 322314d..7f227b7 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
@@ -558,10 +558,10 @@
   protected void removeReplicationServerDB() {
     for (ReplicationServer rs : ReplicationServer.getAllInstances()) {
       StaticUtils.recursiveDelete(new File(DirectoryServer.getInstanceRoot(),
-               rs.getDbDirName()));      
+               rs.getDbDirName()));
     }
   }
-  
+
   /**
    * Performs a search on the config backend with the specified filter.
    * Fails if a config entry is found.
@@ -927,7 +927,7 @@
           + addOperation.getResultCode()
           + " Expected:"
           + expectedResult + " Details:" + addOperation.getErrorMessage()
-          + addOperation.getAdditionalLogMessage());
+          + addOperation.getAdditionalLogItems());
 
       if (expectedResult != ResultCode.SUCCESS)
       {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/IsolationTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/IsolationTest.java
index d4b10a4..a133491 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/IsolationTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/IsolationTest.java
@@ -23,6 +23,7 @@
  *
  *
  *      Copyright 2008-2009 Sun Microsystems, Inc.
+ *      Portions Copyright 2011 ForgeRock AS
  */
 package org.opends.server.replication.plugin;
 
@@ -35,8 +36,6 @@
 
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.ReplicationDomainCfgDefn.IsolationPolicy;
-import org.opends.server.api.SynchronizationProvider;
-import org.opends.server.core.DirectoryServer;
 import org.opends.server.core.ModifyOperation;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.replication.ReplicationTestCase;
@@ -55,8 +54,9 @@
    * Check that the server correctly accept or reject updates when
    * the replication is configured but could not connect to
    * any of the configured replication server.
+   *
+   * @throws Exception If an unexpected error occurred.
    */
-  @SuppressWarnings("unchecked")
   @Test()
   public void noUpdateIsolationPolicyTest() throws Exception
   {
@@ -100,7 +100,7 @@
 
       // check that the operation was successful.
       assertEquals(op.getResultCode(), ResultCode.SUCCESS,
-          op.getAdditionalLogMessage().toString());
+          op.getAdditionalLogItems().toString());
     }
     finally
     {
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AdditionalLogItemTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AdditionalLogItemTest.java
new file mode 100644
index 0000000..c0f80bf
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/types/AdditionalLogItemTest.java
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2011 ForgeRock AS
+ */
+package org.opends.server.types;
+
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Tests for {@link AdditionalLogItem}.
+ */
+public class AdditionalLogItemTest extends TypesTestCase
+{
+
+  /**
+   * Tests {@link AdditionalLogItem#keyOnly(Class, String)}.
+   */
+  @Test
+  public void testKeyOnly()
+  {
+    AdditionalLogItem item = AdditionalLogItem.keyOnly(getClass(), "testKey");
+    assertEquals(item.getSource(), getClass());
+    assertEquals(item.getKey(), "testKey");
+    assertEquals(item.getValue(), null);
+    assertEquals(item.toString(), "testKey");
+    assertEquals(item.toString(new StringBuilder()).toString(), "testKey");
+  }
+
+
+
+  /**
+   * Tests {@link AdditionalLogItem#quotedKeyValue(Class, String, Object)}.
+   */
+  @Test
+  public void testQuotedKeyValue()
+  {
+    AdditionalLogItem item = AdditionalLogItem.quotedKeyValue(getClass(),
+        "testKey", "testValue");
+    assertEquals(item.getSource(), getClass());
+    assertEquals(item.getKey(), "testKey");
+    assertEquals(item.getValue(), "testValue");
+    assertTrue(item.isQuoted());
+    assertEquals(item.toString(), "testKey='testValue'");
+    assertEquals(item.toString(new StringBuilder()).toString(),
+        "testKey='testValue'");
+  }
+
+
+
+  /**
+   * Tests {@link AdditionalLogItem#unquotedKeyValue(Class, String, Object)}.
+   */
+  @Test
+  public void testUnquotedKeyValue()
+  {
+    AdditionalLogItem item = AdditionalLogItem.unquotedKeyValue(getClass(),
+        "testKey", "testValue");
+    assertEquals(item.getSource(), getClass());
+    assertEquals(item.getKey(), "testKey");
+    assertEquals(item.getValue(), "testValue");
+    assertFalse(item.isQuoted());
+    assertEquals(item.toString(), "testKey=testValue");
+    assertEquals(item.toString(new StringBuilder()).toString(),
+        "testKey=testValue");
+  }
+}

--
Gitblit v1.10.0