You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ru...@apache.org on 2008/02/14 17:01:19 UTC

svn commit: r627789 - in /incubator/qpid/branches/M2.1/java/common/src: main/java/org/apache/qpid/framing/ test/java/org/apache/qpid/framing/

Author: rupertlssmith
Date: Thu Feb 14 08:01:15 2008
New Revision: 627789

URL: http://svn.apache.org/viewvc?rev=627789&view=rev
Log:
QPID-9 : Nested field tables implemented. Also wrote a test that encodes/decodes one to check it works.

Modified:
    incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
    incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
    incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
    incubator/qpid/branches/M2.1/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java

Modified: incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQType.java?rev=627789&r1=627788&r2=627789&view=diff
==============================================================================
--- incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQType.java (original)
+++ incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQType.java Thu Feb 14 08:01:15 2008
@@ -23,12 +23,24 @@
 import org.apache.mina.common.ByteBuffer;
 
 import java.math.BigDecimal;
-import java.math.BigInteger;
 
+/**
+ * AMQType is a type that represents the different possible AMQP field table types. It provides operations for each
+ * of the types to perform tasks such as calculating the size of an instance of the type, converting types between AMQP
+ * and Java native types, and reading and writing instances of AMQP types in binary formats to and from byte buffers.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Get the equivalent one byte identifier for a type.
+ * <tr><td> Calculate the size of an instance of an AMQP parameter type. <td> {@link EncodingUtils}
+ * <tr><td> Convert an instance of an AMQP parameter into a compatable Java object tagged with its AMQP type.
+ *     <td> {@link AMQTypedValue}
+ * <tr><td> Write an instance of an AMQP parameter type to a byte buffer. <td> {@link EncodingUtils}
+ * <tr><td> Read an instance of an AMQP parameter from a byte buffer. <td> {@link EncodingUtils}
+ * </table>
+ */
 public enum AMQType
 {
-    //AMQP FieldTable Wire Types
-
     LONG_STRING('S')
     {
         public int getEncodingSize(Object value)
@@ -36,7 +48,6 @@
             return EncodingUtils.encodedLongStringLength((String) value);
         }
 
-
         public String toNativeValue(Object value)
         {
             if (value != null)
@@ -58,12 +69,10 @@
         {
             return EncodingUtils.readLongString(buffer);
         }
-
     },
 
     INTEGER('i')
     {
-
         public int getEncodingSize(Object value)
         {
             return EncodingUtils.unsignedIntegerLength();
@@ -89,12 +98,11 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Long.valueOf((String)value);
+                return Long.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to int.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName() + ") to int.");
             }
         }
 
@@ -111,22 +119,21 @@
 
     DECIMAL('D')
     {
-
         public int getEncodingSize(Object value)
         {
-            return EncodingUtils.encodedByteLength()+ EncodingUtils.encodedIntegerLength();
+            return EncodingUtils.encodedByteLength() + EncodingUtils.encodedIntegerLength();
         }
 
         public Object toNativeValue(Object value)
         {
-            if(value instanceof BigDecimal)
+            if (value instanceof BigDecimal)
             {
                 return (BigDecimal) value;
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to BigDecimal.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to BigDecimal.");
             }
         }
 
@@ -150,7 +157,8 @@
             int unscaled = EncodingUtils.readInteger(buffer);
 
             BigDecimal bd = new BigDecimal(unscaled);
-            return bd.setScale(places);            
+
+            return bd.setScale(places);
         }
     },
 
@@ -163,14 +171,14 @@
 
         public Object toNativeValue(Object value)
         {
-            if(value instanceof Long)
+            if (value instanceof Long)
             {
                 return (Long) value;
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to timestamp.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to timestamp.");
             }
         }
 
@@ -179,37 +187,97 @@
             EncodingUtils.writeLong(buffer, (Long) value);
         }
 
-
         public Object readValueFromBuffer(ByteBuffer buffer)
         {
             return EncodingUtils.readLong(buffer);
         }
     },
 
+    /**
+     * Implements the field table type. The native value of a field table type will be an instance of
+     * {@link FieldTable}, which itself may contain name/value pairs encoded as {@link AMQTypedValue}s.
+     */
     FIELD_TABLE('F')
     {
+        /**
+         * Calculates the size of an instance of the type in bytes.
+         *
+         * @param value An instance of the type.
+         *
+         * @return The size of the instance of the type in bytes.
+         */
         public int getEncodingSize(Object value)
         {
-            // TODO : fixme
-            throw new UnsupportedOperationException();
+            // Ensure that the value is a FieldTable.
+            if (!(value instanceof FieldTable))
+            {
+                throw new IllegalArgumentException("Value is not a FieldTable.");
+            }
+
+            FieldTable ftValue = (FieldTable) value;
+
+            // Loop over all name/value pairs adding up size of each. FieldTable itself keeps track of its encoded
+            // size as entries are added, so no need to loop over all explicitly.
+            // EncodingUtils calculation of the encoded field table lenth, will include 4 bytes for its 'size' field.
+            return EncodingUtils.encodedFieldTableLength(ftValue);
         }
 
+        /**
+         * Converts an instance of the type to an equivalent Java native representation.
+         *
+         * @param value An instance of the type.
+         *
+         * @return An equivalent Java native representation.
+         */
         public Object toNativeValue(Object value)
         {
-            // TODO : fixme
-            throw new UnsupportedOperationException();
+            // Ensure that the value is a FieldTable.
+            if (!(value instanceof FieldTable))
+            {
+                throw new IllegalArgumentException("Value is not a FieldTable.");
+            }
+
+            return (FieldTable) value;
         }
 
+        /**
+         * Writes an instance of the type to a specified byte buffer.
+         *
+         * @param value  An instance of the type.
+         * @param buffer The byte buffer to write it to.
+         */
         public void writeValueImpl(Object value, ByteBuffer buffer)
         {
-            // TODO : fixme
-            throw new UnsupportedOperationException();
+            // Ensure that the value is a FieldTable.
+            if (!(value instanceof FieldTable))
+            {
+                throw new IllegalArgumentException("Value is not a FieldTable.");
+            }
+
+            FieldTable ftValue = (FieldTable) value;
+
+            // Loop over all name/values writing out into buffer.
+            ftValue.writeToBuffer(buffer);
         }
 
+        /**
+         * Reads an instance of the type from a specified byte buffer.
+         *
+         * @param buffer The byte buffer to write it to.
+         *
+         * @return An instance of the type.
+         */
         public Object readValueFromBuffer(ByteBuffer buffer)
         {
-            // TODO : fixme
-            throw new UnsupportedOperationException();
+            try
+            {
+                // Read size of field table then all name/value pairs.
+                return EncodingUtils.readFieldTable(buffer);
+            }
+            catch (AMQFrameDecodingException e)
+            {
+                throw new IllegalArgumentException("Unable to read field table from buffer.", e);
+            }
         }
     },
 
@@ -220,7 +288,6 @@
             return 0;
         }
 
-
         public Object toNativeValue(Object value)
         {
             if (value == null)
@@ -229,14 +296,13 @@
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to null String.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to null String.");
             }
         }
 
         public void writeValueImpl(Object value, ByteBuffer buffer)
-        {
-        }
+        { }
 
         public Object readValueFromBuffer(ByteBuffer buffer)
         {
@@ -244,8 +310,6 @@
         }
     },
 
-    // Extended types
-
     BINARY('x')
     {
         public int getEncodingSize(Object value)
@@ -253,21 +317,19 @@
             return EncodingUtils.encodedLongstrLength((byte[]) value);
         }
 
-
         public Object toNativeValue(Object value)
         {
-            if((value instanceof byte[]) || (value == null))
+            if ((value instanceof byte[]) || (value == null))
             {
                 return value;
             }
             else
             {
-                throw new IllegalArgumentException("Value: " + value + " (" + value.getClass().getName() +
-                                                    ") cannot be converted to byte[]");
+                throw new IllegalArgumentException("Value: " + value + " (" + value.getClass().getName()
+                    + ") cannot be converted to byte[]");
             }
         }
 
-
         public void writeValueImpl(Object value, ByteBuffer buffer)
         {
             EncodingUtils.writeLongstr(buffer, (byte[]) value);
@@ -277,7 +339,6 @@
         {
             return EncodingUtils.readLongstr(buffer);
         }
-
     },
 
     ASCII_STRING('c')
@@ -287,7 +348,6 @@
             return EncodingUtils.encodedLongStringLength((String) value);
         }
 
-
         public String toNativeValue(Object value)
         {
             if (value != null)
@@ -309,7 +369,6 @@
         {
             return EncodingUtils.readLongString(buffer);
         }
-
     },
 
     WIDE_STRING('C')
@@ -320,7 +379,6 @@
             return EncodingUtils.encodedLongStringLength((String) value);
         }
 
-
         public String toNativeValue(Object value)
         {
             if (value != null)
@@ -351,7 +409,6 @@
             return EncodingUtils.encodedBooleanLength();
         }
 
-
         public Object toNativeValue(Object value)
         {
             if (value instanceof Boolean)
@@ -360,12 +417,12 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Boolean.valueOf((String)value);
+                return Boolean.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to boolean.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to boolean.");
             }
         }
 
@@ -374,7 +431,6 @@
             EncodingUtils.writeBoolean(buffer, (Boolean) value);
         }
 
-
         public Object readValueFromBuffer(ByteBuffer buffer)
         {
             return EncodingUtils.readBoolean(buffer);
@@ -388,7 +444,6 @@
             return EncodingUtils.encodedCharLength();
         }
 
-
         public Character toNativeValue(Object value)
         {
             if (value instanceof Character)
@@ -401,8 +456,8 @@
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to char.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to char.");
             }
         }
 
@@ -415,7 +470,6 @@
         {
             return EncodingUtils.readChar(buffer);
         }
-
     },
 
     BYTE('b')
@@ -425,7 +479,6 @@
             return EncodingUtils.encodedByteLength();
         }
 
-
         public Byte toNativeValue(Object value)
         {
             if (value instanceof Byte)
@@ -434,12 +487,12 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Byte.valueOf((String)value);
+                return Byte.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to byte.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to byte.");
             }
         }
 
@@ -456,13 +509,11 @@
 
     SHORT('s')
     {
-
         public int getEncodingSize(Object value)
         {
             return EncodingUtils.encodedShortLength();
         }
 
-
         public Short toNativeValue(Object value)
         {
             if (value instanceof Short)
@@ -475,16 +526,13 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Short.valueOf((String)value);
+                return Short.valueOf((String) value);
             }
-
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to short.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to short.");
             }
-
-
         }
 
         public void writeValueImpl(Object value, ByteBuffer buffer)
@@ -521,12 +569,11 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Integer.valueOf((String)value);
+                return Integer.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to int.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName() + ") to int.");
             }
         }
 
@@ -543,7 +590,6 @@
 
     LONG('l')
     {
-
         public int getEncodingSize(Object value)
         {
             return EncodingUtils.encodedLongLength();
@@ -551,7 +597,7 @@
 
         public Object toNativeValue(Object value)
         {
-            if(value instanceof Long)
+            if (value instanceof Long)
             {
                 return (Long) value;
             }
@@ -569,12 +615,12 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Long.valueOf((String)value);
+                return Long.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to long.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to long.");
             }
         }
 
@@ -583,7 +629,6 @@
             EncodingUtils.writeLong(buffer, (Long) value);
         }
 
-
         public Object readValueFromBuffer(ByteBuffer buffer)
         {
             return EncodingUtils.readLong(buffer);
@@ -597,7 +642,6 @@
             return EncodingUtils.encodedFloatLength();
         }
 
-
         public Float toNativeValue(Object value)
         {
             if (value instanceof Float)
@@ -606,12 +650,12 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Float.valueOf((String)value);
+                return Float.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to float.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to float.");
             }
         }
 
@@ -628,13 +672,11 @@
 
     DOUBLE('d')
     {
-
         public int getEncodingSize(Object value)
         {
             return EncodingUtils.encodedDoubleLength();
         }
 
-
         public Double toNativeValue(Object value)
         {
             if (value instanceof Double)
@@ -647,12 +689,12 @@
             }
             else if ((value instanceof String) || (value == null))
             {
-                return Double.valueOf((String)value);
+                return Double.valueOf((String) value);
             }
             else
             {
-                throw new NumberFormatException("Cannot convert: " + value + "(" +
-                                                value.getClass().getName() + ") to double.");
+                throw new NumberFormatException("Cannot convert: " + value + "(" + value.getClass().getName()
+                    + ") to double.");
             }
         }
 
@@ -667,35 +709,87 @@
         }
     };
 
+    /** Holds the defined one byte identifier for the type. */
     private final byte _identifier;
 
+    /**
+     * Creates an instance of an AMQP type from its defined one byte identifier.
+     *
+     * @param identifier The one byte identifier for the type.
+     */
     AMQType(char identifier)
     {
         _identifier = (byte) identifier;
     }
 
+    /**
+     * Extracts the byte identifier for the typ.
+     *
+     * @return The byte identifier for the typ.
+     */
     public final byte identifier()
     {
         return _identifier;
     }
 
-
+    /**
+     * Calculates the size of an instance of the type in bytes.
+     *
+     * @param value An instance of the type.
+     *
+     * @return The size of the instance of the type in bytes.
+     */
     public abstract int getEncodingSize(Object value);
 
+    /**
+     * Converts an instance of the type to an equivalent Java native representation.
+     *
+     * @param value An instance of the type.
+     *
+     * @return An equivalent Java native representation.
+     */
     public abstract Object toNativeValue(Object value);
 
+    /**
+     * Converts an instance of the type to an equivalent Java native representation, packaged as an
+     * {@link AMQTypedValue} tagged with its AMQP type.
+     *
+     * @param value An instance of the type.
+     *
+     * @return An equivalent Java native representation, tagged with its AMQP type.
+     */
     public AMQTypedValue asTypedValue(Object value)
     {
         return new AMQTypedValue(this, toNativeValue(value));
     }
 
+    /**
+     * Writes an instance of the type to a specified byte buffer, preceded by its one byte identifier. As the type and
+     * value are both written, this provides a fully encoded description of a parameters type and value.
+     *
+     * @param value  An instance of the type.
+     * @param buffer The byte buffer to write it to.
+     */
     public void writeToBuffer(Object value, ByteBuffer buffer)
     {
-        buffer.put((byte)identifier());
+        buffer.put(identifier());
         writeValueImpl(value, buffer);
     }
 
+    /**
+     * Writes an instance of the type to a specified byte buffer.
+     *
+     * @param value  An instance of the type.
+     * @param buffer The byte buffer to write it to.
+     */
     abstract void writeValueImpl(Object value, ByteBuffer buffer);
 
+    /**
+     * Reads an instance of the type from a specified byte buffer.
+     *
+     * @param buffer The byte buffer to write it to.
+     *
+     * @return An instance of the type.
+     */
     abstract Object readValueFromBuffer(ByteBuffer buffer);
 }

Modified: incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java?rev=627789&r1=627788&r2=627789&view=diff
==============================================================================
--- incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java (original)
+++ incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java Thu Feb 14 08:01:15 2008
@@ -18,23 +18,40 @@
  * under the License.
  *
  */
-
 package org.apache.qpid.framing;
 
 import org.apache.mina.common.ByteBuffer;
 
+/**
+ * AMQTypedValue combines together a native Java Object value, and an {@link AMQType}, as a fully typed AMQP parameter
+ * value. It provides the ability to read and write fully typed parameters to and from byte buffers. It also provides
+ * the ability to create such parameters from Java native value and a type tag or to extract the native value and type
+ * from one.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Create a fully typed AMQP value from a native type and a type tag. <td> {@link AMQType}
+ * <tr><td> Create a fully typed AMQP value from a binary representation in a byte buffer. <td> {@link AMQType}
+ * <tr><td> Write a fully typed AMQP value to a binary representation in a byte buffer. <td> {@link AMQType}
+ * <tr><td> Extract the type from a fully typed AMQP value.
+ * <tr><td> Extract the value from a fully typed AMQP value.
+ * </table>
+ */
 public class AMQTypedValue
 {
+    /** The type of the value. */
     private final AMQType _type;
-    private final Object _value;
 
+    /** The Java native representation of the AMQP typed value. */
+    private final Object _value;
 
     public AMQTypedValue(AMQType type, Object value)
     {
-        if(type == null)
+        if (type == null)
         {
             throw new NullPointerException("Cannot create a typed value with null type");
         }
+
         _type = type;
         _value = type.toNativeValue(value);
     }
@@ -42,10 +59,9 @@
     private AMQTypedValue(AMQType type, ByteBuffer buffer)
     {
         _type = type;
-        _value = type.readValueFromBuffer( buffer );
+        _value = type.readValueFromBuffer(buffer);
     }
 
-
     public AMQType getType()
     {
         return _type;
@@ -56,10 +72,9 @@
         return _value;
     }
 
-
     public void writeToBuffer(ByteBuffer buffer)
     {
-        _type.writeToBuffer(_value,buffer);
+        _type.writeToBuffer(_value, buffer);
     }
 
     public int getEncodingSize()
@@ -70,11 +85,12 @@
     public static AMQTypedValue readFromBuffer(ByteBuffer buffer)
     {
         AMQType type = AMQTypeMap.getType(buffer.get());
+
         return new AMQTypedValue(type, buffer);
     }
 
     public String toString()
     {
-        return "["+getType()+": "+getValue()+"]";
+        return "[" + getType() + ": " + getValue() + "]";
     }
 }

Modified: incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java?rev=627789&r1=627788&r2=627789&view=diff
==============================================================================
--- incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java (original)
+++ incubator/qpid/branches/M2.1/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java Thu Feb 14 08:01:15 2008
@@ -18,7 +18,6 @@
  * under the License.
  *
  */
-
 package org.apache.qpid.framing;
 
 import org.apache.mina.common.ByteBuffer;
@@ -360,6 +359,41 @@
         }
     }
 
+    /**
+     * Extracts a value from the field table that is itself a FieldTable associated with the specified parameter name.
+     *
+     * @param string The name of the parameter to get the associated FieldTable value for.
+     *
+     * @return The associated FieldTable value, or <tt>null</tt> if the associated value is not of FieldTable type or
+     *         not present in the field table at all.
+     */
+    public FieldTable getFieldTable(String string)
+    {
+        return getFieldTable(new AMQShortString(string));
+    }
+
+    /**
+     * Extracts a value from the field table that is itself a FieldTable associated with the specified parameter name.
+     *
+     * @param string The name of the parameter to get the associated FieldTable value for.
+     *
+     * @return The associated FieldTable value, or <tt>null</tt> if the associated value is not of FieldTable type or
+     *         not present in the field table at all.
+     */
+    public FieldTable getFieldTable(AMQShortString string)
+    {
+        AMQTypedValue value = getProperty(string);
+
+        if ((value != null) && (value.getType() == AMQType.FIELD_TABLE))
+        {
+            return (FieldTable) value.getValue();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
     public Object getObject(String string)
     {
         return getObject(new AMQShortString(string));
@@ -566,6 +600,32 @@
     public Object setVoid(AMQShortString string)
     {
         return setProperty(string, AMQType.VOID.asTypedValue(null));
+    }
+
+    /**
+     * Associates a nested field table with the specified parameter name.
+     *
+     * @param string  The name of the parameter to store in the table.
+     * @param ftValue The field table value to associate with the parameter name.
+     *
+     * @return The stored value.
+     */
+    public Object setFieldTable(String string, FieldTable ftValue)
+    {
+        return setFieldTable(new AMQShortString(string), ftValue);
+    }
+
+    /**
+     * Associates a nested field table with the specified parameter name.
+     *
+     * @param string  The name of the parameter to store in the table.
+     * @param ftValue The field table value to associate with the parameter name.
+     *
+     * @return The stored value.
+     */
+    public Object setFieldTable(AMQShortString string, FieldTable ftValue)
+    {
+        return setProperty(string, AMQType.FIELD_TABLE.asTypedValue(ftValue));
     }
 
     public Object setObject(AMQShortString string, Object object)

Modified: incubator/qpid/branches/M2.1/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
URL: http://svn.apache.org/viewvc/incubator/qpid/branches/M2.1/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java?rev=627789&r1=627788&r2=627789&view=diff
==============================================================================
--- incubator/qpid/branches/M2.1/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java (original)
+++ incubator/qpid/branches/M2.1/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java Thu Feb 14 08:01:15 2008
@@ -1,21 +1,21 @@
 /*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  *
  */
 package org.apache.qpid.framing;
@@ -437,6 +437,60 @@
         table1.setObject("value", "Hello");
         // Check that it was set correctly
         Assert.assertEquals("Hello", table1.getString("value"));
+    }
+
+    /** Check that a nested field table parameter correctly encodes and decodes to a byte buffer. */
+    public void testNestedFieldTable()
+    {
+        byte[] testBytes = new byte[] { 0, 1, 2, 3, 4, 5 };
+
+        FieldTable outerTable = new FieldTable();
+        FieldTable innerTable = new FieldTable();
+
+        // Put some stuff in the inner table.
+        innerTable.setBoolean("bool", true);
+        innerTable.setByte("byte", Byte.MAX_VALUE);
+        innerTable.setBytes("bytes", testBytes);
+        innerTable.setChar("char", 'c');
+        innerTable.setDouble("double", Double.MAX_VALUE);
+        innerTable.setFloat("float", Float.MAX_VALUE);
+        innerTable.setInteger("int", Integer.MAX_VALUE);
+        innerTable.setLong("long", Long.MAX_VALUE);
+        innerTable.setShort("short", Short.MAX_VALUE);
+        innerTable.setString("string", "hello");
+        innerTable.setString("null-string", null);
+
+        // Put the inner table in the outer one.
+        outerTable.setFieldTable("innerTable", innerTable);
+
+        // Write the outer table into the buffer.
+        final ByteBuffer buffer = ByteBuffer.allocate((int) outerTable.getEncodedSize() + 4);
+        outerTable.writeToBuffer(buffer);
+        buffer.flip();
+
+        // Extract the table back from the buffer again.
+        try
+        {
+            FieldTable extractedOuterTable = EncodingUtils.readFieldTable(buffer);
+
+            FieldTable extractedTable = extractedOuterTable.getFieldTable("innerTable");
+
+            Assert.assertEquals((Boolean) true, extractedTable.getBoolean("bool"));
+            Assert.assertEquals((Byte) Byte.MAX_VALUE, extractedTable.getByte("byte"));
+            assertBytesEqual(testBytes, extractedTable.getBytes("bytes"));
+            Assert.assertEquals((Character) 'c', extractedTable.getCharacter("char"));
+            Assert.assertEquals(Double.MAX_VALUE, extractedTable.getDouble("double"));
+            Assert.assertEquals(Float.MAX_VALUE, extractedTable.getFloat("float"));
+            Assert.assertEquals((Integer) Integer.MAX_VALUE, extractedTable.getInteger("int"));
+            Assert.assertEquals((Long) Long.MAX_VALUE, extractedTable.getLong("long"));
+            Assert.assertEquals((Short) Short.MAX_VALUE, extractedTable.getShort("short"));
+            Assert.assertEquals("hello", extractedTable.getString("string"));
+            Assert.assertEquals(null, extractedTable.getString("null-string"));
+        }
+        catch (AMQFrameDecodingException e)
+        {
+            fail("Failed to decode field table with nested inner table.");
+        }
     }
 
     public void testValues()