PROTON-2380 Improve output of frame traces for various AMQP types

Improves the logging output for several of the AMQP types by reporting
the actual state of the fields when logged (null if not set) and
stringifying the buffer payloads of several types.
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/engine/util/StringUtils.java b/protonj2/src/main/java/org/apache/qpid/protonj2/engine/util/StringUtils.java
index 868de4d..2b1d2e8 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/engine/util/StringUtils.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/engine/util/StringUtils.java
@@ -28,7 +28,6 @@
 import java.util.Set;
 
 import org.apache.qpid.protonj2.buffer.ProtonBuffer;
-import org.apache.qpid.protonj2.buffer.ProtonByteBufferAllocator;
 import org.apache.qpid.protonj2.types.Binary;
 import org.apache.qpid.protonj2.types.Symbol;
 
@@ -37,14 +36,16 @@
  */
 public class StringUtils {
 
-	/**
-	 * Converts the given String[] into a Symbol[] array.
-	 *
-	 * @param stringArray
-	 * 		The given String[] to convert.
-	 *
-	 * @return a new Symbol array that contains Symbol versions of the input Strings.
-	 */
+    private static final int DEFAULT_QUOTED_STRING_LIMIT = 64;
+
+    /**
+     * Converts the given String[] into a Symbol[] array.
+     *
+     * @param stringArray
+     * 		The given String[] to convert.
+     *
+     * @return a new Symbol array that contains Symbol versions of the input Strings.
+     */
     public static Symbol[] toSymbolArray(String[] stringArray) {
         Symbol[] result = null;
 
@@ -58,14 +59,14 @@
         return result;
     }
 
-	/**
-	 * Converts the given Symbol[] into a String[] array.
-	 *
-	 * @param symbolArray
-	 * 		The given Symbol[] to convert.
-	 *
-	 * @return a new String array that contains String versions of the input Symbol.
-	 */
+    /**
+     * Converts the given Symbol[] into a String[] array.
+     *
+     * @param symbolArray
+     * 		The given Symbol[] to convert.
+     *
+     * @return a new String array that contains String versions of the input Symbol.
+     */
     public static String[] toStringArray(Symbol[] symbolArray) {
         String[] result = null;
 
@@ -79,14 +80,14 @@
         return result;
     }
 
-	/**
-	 * Converts the given String keyed {@link Map} into a matching Symbol keyed {@link Map}.
-	 *
-	 * @param stringsMap
-	 * 		The given String keyed {@link Map} to convert.
-	 *
-	 * @return a new Symbol keyed {@link Map} that contains Symbol versions of the input String keys.
-	 */
+    /**
+     * Converts the given String keyed {@link Map} into a matching Symbol keyed {@link Map}.
+     *
+     * @param stringsMap
+     * 		The given String keyed {@link Map} to convert.
+     *
+     * @return a new Symbol keyed {@link Map} that contains Symbol versions of the input String keys.
+     */
     public static Map<Symbol, Object> toSymbolKeyedMap(Map<String, Object> stringsMap) {
         final Map<Symbol, Object> result;
 
@@ -102,14 +103,14 @@
         return result;
     }
 
-	/**
-	 * Converts the given Symbol keyed {@link Map} into a matching String keyed {@link Map}.
-	 *
-	 * @param symbolMap
-	 * 		The given String keyed {@link Map} to convert.
-	 *
-	 * @return a new String keyed {@link Map} that contains String versions of the input Symbol keys.
-	 */
+    /**
+     * Converts the given Symbol keyed {@link Map} into a matching String keyed {@link Map}.
+     *
+     * @param symbolMap
+     * 		The given String keyed {@link Map} to convert.
+     *
+     * @return a new String keyed {@link Map} that contains String versions of the input Symbol keys.
+     */
     public static Map<String, Object> toStringKeyedMap(Map<Symbol, Object> symbolMap) {
         Map<String, Object> result;
 
@@ -125,14 +126,14 @@
         return result;
     }
 
-	/**
-	 * Converts the given String {@link Collection} into a Symbol array.
-	 *
-	 * @param stringsSet
-	 * 		The given String {@link Collection} to convert.
-	 *
-	 * @return a new Symbol array that contains String versions of the input Symbols.
-	 */
+    /**
+     * Converts the given String {@link Collection} into a Symbol array.
+     *
+     * @param stringsSet
+     * 		The given String {@link Collection} to convert.
+     *
+     * @return a new Symbol array that contains String versions of the input Symbols.
+     */
     public static Symbol[] toSymbolArray(Collection<String> stringsSet) {
         final Symbol[] result;
 
@@ -149,14 +150,14 @@
         return result;
     }
 
-	/**
-	 * Converts the given String {@link Collection} into a matching Symbol {@link Set}.
-	 *
-	 * @param stringsSet
-	 * 		The given String {@link Collection} to convert.
-	 *
-	 * @return a new Symbol {@link Set} that contains String versions of the input Symbols.
-	 */
+    /**
+     * Converts the given String {@link Collection} into a matching Symbol {@link Set}.
+     *
+     * @param stringsSet
+     * 		The given String {@link Collection} to convert.
+     *
+     * @return a new Symbol {@link Set} that contains String versions of the input Symbols.
+     */
     public static Set<Symbol> toSymbolSet(Collection<String> stringsSet) {
         final Set<Symbol> result;
 
@@ -172,14 +173,14 @@
         return result;
     }
 
-	/**
-	 * Converts the given Symbol array into a matching String {@link Set}.
-	 *
-	 * @param symbols
-	 * 		The given Symbol array to convert.
-	 *
-	 * @return a new String {@link Set} that contains String versions of the input Symbols.
-	 */
+    /**
+     * Converts the given Symbol array into a matching String {@link Set}.
+     *
+     * @param symbols
+     * 		The given Symbol array to convert.
+     *
+     * @return a new String {@link Set} that contains String versions of the input Symbols.
+     */
     public static Set<String> toStringSet(Symbol[] symbols) {
         Set<String> result;
 
@@ -196,6 +197,33 @@
     }
 
     /**
+     * Converts the Binary to a quoted string using a default max length before truncation value and
+     * appends a truncation indication if the string required truncation.
+     *
+     * @param buffer
+     *        the {@link Binary} to convert into String format.
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final Binary buffer) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, true);
+    }
+
+    /**
+     * Converts the Binary to a quoted string using a default max length before truncation value.
+     *
+     * @param buffer
+     *        the {@link Binary} to convert into String format.
+     * @param appendIfTruncated
+     *        appends "...(truncated)" if not all of the payload is present in the string
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final Binary buffer, final boolean appendIfTruncated) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, appendIfTruncated);
+    }
+
+    /**
      * Converts the Binary to a quoted string.
      *
      * @param buffer
@@ -210,11 +238,36 @@
     public static String toQuotedString(final Binary buffer, final int stringLength, final boolean appendIfTruncated) {
         if (buffer == null) {
             return "\"\"";
+        } else {
+            return toQuotedString(buffer.asProtonBuffer(), stringLength, appendIfTruncated);
         }
+    }
 
-        ProtonBuffer wrapped = ProtonByteBufferAllocator.DEFAULT.wrap(buffer.getArray(), buffer.getArrayOffset(), buffer.getLength());
+    /**
+     * Converts the ProtonBuffer to a quoted string using a default max length before truncation value and
+     * appends a truncation indication if the string required truncation.
+     *
+     * @param buffer
+     *        the {@link ProtonBuffer} to convert into String format.
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final ProtonBuffer buffer) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, true);
+    }
 
-        return toQuotedString(wrapped, stringLength, appendIfTruncated);
+    /**
+     * Converts the ProtonBuffer to a quoted string using a default max length before truncation value.
+     *
+     * @param buffer
+     *        the {@link ProtonBuffer} to convert into String format.
+     * @param appendIfTruncated
+     *        appends "...(truncated)" if not all of the payload is present in the string
+     *
+     * @return the converted string
+     */
+    public static String toQuotedString(final ProtonBuffer buffer, final boolean appendIfTruncated) {
+        return toQuotedString(buffer, DEFAULT_QUOTED_STRING_LIMIT, appendIfTruncated);
     }
 
     /**
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Header.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Header.java
index 72d5085..a83f481 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Header.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Header.java
@@ -227,11 +227,12 @@
     @Override
     public String toString() {
         return "Header{ " +
-                "durable=" + durable +
-                ", priority=" + priority +
-                ", ttl=" + timeToLive +
-                ", firstAcquirer=" + firstAcquirer +
-                ", deliveryCount=" + deliveryCount + " }";
+                "durable=" + (hasDurable() ? durable : "null") +
+                ", priority=" + (hasPriority() ? priority : "null") +
+                ", ttl=" + (hasTimeToLive() ? timeToLive : "null") +
+                ", firstAcquirer=" + (hasFirstAcquirer() ? firstAcquirer : "null") +
+                ", deliveryCount=" + (hasDeliveryCount() ? deliveryCount : "null") +
+                " }";
     }
 
     @Override
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Properties.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Properties.java
index 8f7b10d..5ca5f42 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Properties.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/messaging/Properties.java
@@ -410,10 +410,10 @@
                 ", correlationId=" + correlationId +
                 ", contentType=" + contentType +
                 ", contentEncoding=" + contentEncoding +
-                ", absoluteExpiryTime=" + absoluteExpiryTime +
-                ", creationTime=" + creationTime +
+                ", absoluteExpiryTime=" + (hasAbsoluteExpiryTime() ? absoluteExpiryTime : "null") +
+                ", creationTime=" + (hasCreationTime() ? creationTime : null) +
                 ", groupId='" + groupId + '\'' +
-                ", groupSequence=" + groupSequence +
+                ", groupSequence=" + (hasGroupSequence() ? groupSequence : null) +
                 ", replyToGroupId='" + replyToGroupId + '\'' + " }";
     }
 
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslChallenge.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslChallenge.java
index 5e2eeeb..596d418 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslChallenge.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslChallenge.java
@@ -19,6 +19,7 @@
 import java.util.Objects;
 
 import org.apache.qpid.protonj2.buffer.ProtonBuffer;
+import org.apache.qpid.protonj2.engine.util.StringUtils;
 import org.apache.qpid.protonj2.types.Binary;
 import org.apache.qpid.protonj2.types.Symbol;
 import org.apache.qpid.protonj2.types.UnsignedLong;
@@ -57,7 +58,7 @@
 
     @Override
     public String toString() {
-        return "SaslChallenge{" + "challenge=" + challenge + '}';
+        return "SaslChallenge{" + "challenge=" + (challenge == null ? null : StringUtils.toQuotedString(challenge)) + '}';
     }
 
     @Override
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslInit.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslInit.java
index ddf7eee..051cc39 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslInit.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslInit.java
@@ -17,6 +17,7 @@
 package org.apache.qpid.protonj2.types.security;
 
 import org.apache.qpid.protonj2.buffer.ProtonBuffer;
+import org.apache.qpid.protonj2.engine.util.StringUtils;
 import org.apache.qpid.protonj2.types.Binary;
 import org.apache.qpid.protonj2.types.Symbol;
 import org.apache.qpid.protonj2.types.UnsignedLong;
@@ -83,7 +84,7 @@
     public String toString() {
         return "SaslInit{" +
                "mechanism=" + mechanism +
-               ", initialResponse=" + initialResponse +
+               ", initialResponse=" + (initialResponse == null ? null : StringUtils.toQuotedString(initialResponse)) +
                ", hostname='" + hostname + '\'' + '}';
     }
 
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslOutcome.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslOutcome.java
index 255f2e6..f0f9fb1 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslOutcome.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslOutcome.java
@@ -17,6 +17,7 @@
 package org.apache.qpid.protonj2.types.security;
 
 import org.apache.qpid.protonj2.buffer.ProtonBuffer;
+import org.apache.qpid.protonj2.engine.util.StringUtils;
 import org.apache.qpid.protonj2.types.Binary;
 import org.apache.qpid.protonj2.types.Symbol;
 import org.apache.qpid.protonj2.types.UnsignedLong;
@@ -70,7 +71,10 @@
 
     @Override
     public String toString() {
-        return "SaslOutcome{" + "_code=" + code + ", _additionalData=" + additionalData + '}';
+        return "SaslOutcome{" +
+               "code=" + code +
+               ", additionalData=" + (additionalData == null ? null : StringUtils.toQuotedString(additionalData)) +
+               '}';
     }
 
     @Override
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslResponse.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslResponse.java
index b7ee786..2cd9bc1 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslResponse.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/security/SaslResponse.java
@@ -19,6 +19,7 @@
 import java.util.Objects;
 
 import org.apache.qpid.protonj2.buffer.ProtonBuffer;
+import org.apache.qpid.protonj2.engine.util.StringUtils;
 import org.apache.qpid.protonj2.types.Binary;
 import org.apache.qpid.protonj2.types.Symbol;
 import org.apache.qpid.protonj2.types.UnsignedLong;
@@ -48,7 +49,7 @@
 
     @Override
     public String toString() {
-        return "SaslResponse{" + "response=" + response + '}';
+        return "SaslResponse{" + "response=" + (response == null ? null : StringUtils.toQuotedString(response)) + '}';
     }
 
     @Override
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Attach.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Attach.java
index 850e9d6..fc50ef0 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Attach.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Attach.java
@@ -451,18 +451,18 @@
     public String toString() {
         return "Attach{" +
             "name='" + name + '\'' +
-            ", handle=" + handle +
-            ", role=" + role +
-            ", sndSettleMode=" + sndSettleMode +
-            ", rcvSettleMode=" + rcvSettleMode +
+            ", handle=" + (hasHandle() ? handle : "null") +
+            ", role=" + (hasRole() ? role : "null") +
+            ", sndSettleMode=" + (hasSenderSettleMode() ? sndSettleMode : "null") +
+            ", rcvSettleMode=" + (hasReceiverSettleMode() ? rcvSettleMode : "null") +
             ", source=" + source +
             ", target=" + target +
             ", unsettled=" + unsettled +
-            ", incompleteUnsettled=" + incompleteUnsettled +
-            ", initialDeliveryCount=" + initialDeliveryCount +
+            ", incompleteUnsettled=" + (hasIncompleteUnsettled() ? incompleteUnsettled : "null") +
+            ", initialDeliveryCount=" + (hasInitialDeliveryCount() ? initialDeliveryCount : "null") +
             ", maxMessageSize=" + maxMessageSize +
-            ", offeredCapabilities=" + (offeredCapabilities == null ? null : Arrays.asList(offeredCapabilities)) +
-            ", desiredCapabilities=" + (desiredCapabilities == null ? null : Arrays.asList(desiredCapabilities)) +
+            ", offeredCapabilities=" + (offeredCapabilities == null ? "null" : Arrays.asList(offeredCapabilities)) +
+            ", desiredCapabilities=" + (desiredCapabilities == null ? "null" : Arrays.asList(desiredCapabilities)) +
             ", properties=" + properties + '}';
     }
 }
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Begin.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Begin.java
index ee5e57b..894ac0e 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Begin.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Begin.java
@@ -282,13 +282,13 @@
     @Override
     public String toString() {
         return "Begin{" +
-               "remoteChannel=" + remoteChannel +
-               ", nextOutgoingId=" + nextOutgoingId +
-               ", incomingWindow=" + incomingWindow +
-               ", outgoingWindow=" + outgoingWindow +
-               ", handleMax=" + handleMax +
-               ", offeredCapabilities=" + (offeredCapabilities == null ? null : Arrays.asList(offeredCapabilities)) +
-               ", desiredCapabilities=" + (desiredCapabilities == null ? null : Arrays.asList(desiredCapabilities)) +
+               "remoteChannel=" + (hasRemoteChannel() ? remoteChannel : "null") +
+               ", nextOutgoingId=" + (hasNextOutgoingId() ? nextOutgoingId : "null") +
+               ", incomingWindow=" + (hasIncomingWindow() ? incomingWindow : "null") +
+               ", outgoingWindow=" + (hasOutgoingWindow() ? outgoingWindow : "null") +
+               ", handleMax=" + (hasHandleMax() ? handleMax : "null") +
+               ", offeredCapabilities=" + (offeredCapabilities == null ? "null" : Arrays.asList(offeredCapabilities)) +
+               ", desiredCapabilities=" + (desiredCapabilities == null ? "null" : Arrays.asList(desiredCapabilities)) +
                ", properties=" + properties +
                '}';
     }
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Detach.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Detach.java
index 0003f85..0a1b756 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Detach.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Detach.java
@@ -130,8 +130,8 @@
     @Override
     public String toString() {
         return "Detach{" +
-               "handle=" + handle +
-               ", closed=" + closed +
+               "handle=" + (hasHandle() ? handle : "null") +
+               ", closed=" + (hasClosed() ? closed : "null") +
                ", error=" + error +
                '}';
     }
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Flow.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Flow.java
index 7b38cdd..38e06e3 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Flow.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Flow.java
@@ -438,16 +438,16 @@
     @Override
     public String toString() {
         return "Flow{" +
-               "nextIncomingId=" + nextIncomingId +
-               ", incomingWindow=" + incomingWindow +
-               ", nextOutgoingId=" + nextOutgoingId +
-               ", outgoingWindow=" + outgoingWindow +
-               ", handle=" + handle +
-               ", deliveryCount=" + deliveryCount +
-               ", linkCredit=" + linkCredit +
-               ", available=" + available +
-               ", drain=" + drain +
-               ", echo=" + echo +
+               "nextIncomingId=" + (hasNextIncomingId() ? nextIncomingId : "null") +
+               ", incomingWindow=" + (hasIncomingWindow() ? incomingWindow : "null") +
+               ", nextOutgoingId=" + (hasNextOutgoingId() ? nextOutgoingId : "null") +
+               ", outgoingWindow=" + (hasOutgoingWindow() ? outgoingWindow : "null") +
+               ", handle=" + (hasHandle() ? handle : "null") +
+               ", deliveryCount=" + (hasDeliveryCount() ? deliveryCount : "null") +
+               ", linkCredit=" + (hasLinkCredit() ? linkCredit : "null") +
+               ", available=" + (hasAvailable() ? available : "null") +
+               ", drain=" + (hasDrain() ? drain : "null") +
+               ", echo=" + (hasEcho() ? echo : "null") +
                ", properties=" + properties +
                '}';
     }
diff --git a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Open.java b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Open.java
index 4275e1d..94260cf 100644
--- a/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Open.java
+++ b/protonj2/src/main/java/org/apache/qpid/protonj2/types/transport/Open.java
@@ -335,13 +335,13 @@
         return "Open{" +
                " containerId='" + containerId + '\'' +
                ", hostname='" + hostname + '\'' +
-               ", maxFrameSize=" + maxFrameSize +
-               ", channelMax=" + channelMax +
-               ", idleTimeOut=" + idleTimeout +
-               ", outgoingLocales=" + (outgoingLocales == null ? null : Arrays.asList(outgoingLocales)) +
-               ", incomingLocales=" + (incomingLocales == null ? null : Arrays.asList(incomingLocales)) +
-               ", offeredCapabilities=" + (offeredCapabilities == null ? null : Arrays.asList(offeredCapabilities)) +
-               ", desiredCapabilities=" + (desiredCapabilities == null ? null : Arrays.asList(desiredCapabilities)) +
+               ", maxFrameSize=" + (hasMaxFrameSize() ? maxFrameSize : "null") +
+               ", channelMax=" + (hasChannelMax() ? channelMax : "null") +
+               ", idleTimeOut=" + (hasIdleTimeout() ? idleTimeout : "null") +
+               ", outgoingLocales=" + (outgoingLocales == null ? "null" : Arrays.asList(outgoingLocales)) +
+               ", incomingLocales=" + (incomingLocales == null ? "null" : Arrays.asList(incomingLocales)) +
+               ", offeredCapabilities=" + (offeredCapabilities == null ? "null" : Arrays.asList(offeredCapabilities)) +
+               ", desiredCapabilities=" + (desiredCapabilities == null ? "null" : Arrays.asList(desiredCapabilities)) +
                ", properties=" + properties +
                '}';
     }