You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ri...@apache.org on 2006/12/05 19:37:21 UTC

svn commit: r482733 [2/2] - in /incubator/qpid/trunk/qpid/java: broker/src/main/java/org/apache/qpid/server/exchange/ broker/src/main/java/org/apache/qpid/server/security/auth/amqplain/ client/src/main/java/org/apache/qpid/client/ client/src/main/java/...

Modified: incubator/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java?view=diff&rev=482733&r1=482732&r2=482733
==============================================================================
--- incubator/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java (original)
+++ incubator/qpid/trunk/qpid/java/common/src/main/java/org/apache/qpid/framing/PropertyFieldTable.java Tue Dec  5 10:37:18 2006
@@ -21,20 +21,28 @@
 package org.apache.qpid.framing;
 
 import org.apache.log4j.Logger;
+import org.apache.mina.common.ByteBuffer;
 
+import java.util.Collection;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
 //extends FieldTable
-public class PropertyFieldTable
+public class PropertyFieldTable implements FieldTable, Map
 {
-
     private static final Logger _logger = Logger.getLogger(PropertyFieldTable.class);
 
+
+    public static final char AMQP_DECIMAL_PROPERTY_PREFIX = 'D';
+    public static final char AMQP_UNSIGNEDINT_PROPERTY_PREFIX = 'I';
+    public static final char AMQP_TIMESTAMP_PROPERTY_PREFIX = 'T';
+    public static final char AMQP_STRING_PROPERTY_PREFIX = 'S';
+
     public static final char BOOLEAN_PROPERTY_PREFIX = 'B';
     public static final char BYTE_PROPERTY_PREFIX = 'b';
     public static final char SHORT_PROPERTY_PREFIX = 's';
@@ -42,10 +50,12 @@
     public static final char LONG_PROPERTY_PREFIX = 'l';
     public static final char FLOAT_PROPERTY_PREFIX = 'f';
     public static final char DOUBLE_PROPERTY_PREFIX = 'd';
-    public static final char STRING_PROPERTY_PREFIX = 'S';
+    public static final char STRING_PROPERTY_PREFIX = AMQP_STRING_PROPERTY_PREFIX;
     public static final char CHAR_PROPERTY_PREFIX = 'c';
     public static final char BYTES_PROPERTY_PREFIX = 'y';
 
+    //Our custom prefix for encoding across the wire
+    private static final char XML_PROPERTY_PREFIX = 'X';
 
     private static final String BOOLEAN = "boolean";
     private static final String BYTE = "byte";
@@ -66,7 +76,7 @@
 
     private LinkedHashMap<String, Object> _properties;
     private LinkedHashMap<String, String> _propertyNamesTypeMap;
-
+    private long _encodedSize = 0;
 
     public PropertyFieldTable()
     {
@@ -84,73 +94,167 @@
         }
         catch (Exception e)
         {
-            System.out.println(textFormat);
-            e.printStackTrace();
+            _logger.error("Unable to decode PropertyFieldTable format:" + textFormat, e);
         }
+    }
 
+    /**
+     * Construct a new field table.
+     *
+     * @param buffer the buffer from which to read data. The length byte must be read already
+     * @param length the length of the field table. Must be > 0.
+     * @throws AMQFrameDecodingException if there is an error decoding the table
+     */
+    public PropertyFieldTable(ByteBuffer buffer, long length) throws AMQFrameDecodingException
+    {
+        this();
+        setFromBuffer(buffer, length);
     }
 
     // ************  Getters
 
+    private Object get(String propertyName, char prefix)
+    {
+        String type = _propertyNamesTypeMap.get(propertyName);
+
+        if (type == null)
+        {
+            return null;
+        }
+        
+        if (type.equals("" + prefix))
+        {
+            return _properties.get(propertyName);
+        }
+        else
+        {
+            return null;
+        }
+    }
+
     public Boolean getBoolean(String string)
     {
-        return (Boolean) _properties.get(BOOLEAN_PROPERTY_PREFIX + string);
+        Object o = get(string, BOOLEAN_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Boolean) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Byte getByte(String string)
     {
-        return (Byte) _properties.get(BYTE_PROPERTY_PREFIX + string);
+        Object o = get(string, BYTE_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Byte) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Short getShort(String string)
     {
-        return (Short) _properties.get(SHORT_PROPERTY_PREFIX + string);
+        Object o = get(string, SHORT_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Short) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Integer getInteger(String string)
     {
-        return (Integer) _properties.get(INT_PROPERTY_PREFIX + string);
+        Object o = get(string, INT_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Integer) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Long getLong(String string)
     {
-        return (Long) _properties.get(LONG_PROPERTY_PREFIX + string);
+        Object o = get(string, LONG_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Long) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Float getFloat(String string)
     {
-        return (Float) _properties.get(FLOAT_PROPERTY_PREFIX + string);
+        Object o = get(string, FLOAT_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Float) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Double getDouble(String string)
     {
-        return (Double) _properties.get(DOUBLE_PROPERTY_PREFIX + string);
+        Object o = get(string, DOUBLE_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Double) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public String getString(String string)
     {
-        return (String) _properties.get(STRING_PROPERTY_PREFIX + string);
+        Object o = get(string, STRING_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (String) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public Character getCharacter(String string)
     {
-        return (Character) _properties.get(CHAR_PROPERTY_PREFIX + string);
+        Object o = get(string, CHAR_PROPERTY_PREFIX);
+        if (o != null)
+        {
+            return (Character) o;
+        }
+        else
+        {
+            return null;
+        }
     }
 
     public byte[] getBytes(String string)
     {
-        return (byte[]) _properties.get(BYTES_PROPERTY_PREFIX + string);
-    }
-
-    public Object getObject(String string)
-    {
-        String typestring = _propertyNamesTypeMap.get(string);
-
-        if (typestring != null && !typestring.equals(""))
+        Object o = get(string, BYTES_PROPERTY_PREFIX);
+        if (o != null)
         {
-            char type = typestring.charAt(0);
-
-            return _properties.get(type + string);
+            return (byte[]) o;
         }
         else
         {
@@ -158,91 +262,66 @@
         }
     }
 
-    // ************  Setters
-
-
-    public void setBoolean(String string, boolean b)
+    public Object getObject(String string)
     {
-        checkPropertyName(string, BOOLEAN_PROPERTY_PREFIX);
+        return _properties.get(string);
+    }
 
+    // ************  Setters
 
-        _propertyNamesTypeMap.put(string, "" + BOOLEAN_PROPERTY_PREFIX);
-        _properties.put(BOOLEAN_PROPERTY_PREFIX + string, b);// ? new Long(1) : new Long(0));
+    public Object setBoolean(String string, boolean b)
+    {
+        return put(BOOLEAN_PROPERTY_PREFIX + string, b);
     }
 
-    public void setByte(String string, byte b)
+    public Object setByte(String string, byte b)
     {
-        checkPropertyName(string, BYTE_PROPERTY_PREFIX);
-
-
-        _properties.put(BYTE_PROPERTY_PREFIX + string, b);
+        return put(BYTE_PROPERTY_PREFIX + string, b);
     }
 
-    public void setShort(String string, short i)
+    public Object setShort(String string, short i)
     {
-        checkPropertyName(string, SHORT_PROPERTY_PREFIX);
-
-
-        _properties.put(SHORT_PROPERTY_PREFIX + string, i);
+        return put(SHORT_PROPERTY_PREFIX + string, i);
     }
 
-    public void setInteger(String string, int i)
+    public Object setInteger(String string, int i)
     {
-        checkPropertyName(string, INT_PROPERTY_PREFIX);
-
-
-        _properties.put(INT_PROPERTY_PREFIX + string, i);
+        return put(INT_PROPERTY_PREFIX + string, i);
     }
 
-    public void setLong(String string, long l)
+    public Object setLong(String string, long l)
     {
-        checkPropertyName(string, LONG_PROPERTY_PREFIX);
-
-
-        _properties.put(LONG_PROPERTY_PREFIX + string, l);
+        return put(LONG_PROPERTY_PREFIX + string, l);
     }
 
-    public void setFloat(String string, float v)
+    public Object setFloat(String string, float v)
     {
-        checkPropertyName(string, FLOAT_PROPERTY_PREFIX);
-
-
-        _properties.put(FLOAT_PROPERTY_PREFIX + string, v);
+        return put(FLOAT_PROPERTY_PREFIX + string, v);
     }
 
-    public void setDouble(String string, double v)
+    public Object setDouble(String string, double v)
     {
-        checkPropertyName(string, DOUBLE_PROPERTY_PREFIX);
-
-
-        _properties.put(DOUBLE_PROPERTY_PREFIX + string, v);
+        return put(DOUBLE_PROPERTY_PREFIX + string, v);
     }
 
-    public void setString(String string, String string1)
+    public Object setString(String string, String string1)
     {
-        checkPropertyName(string, STRING_PROPERTY_PREFIX);
-
-
-        _properties.put(STRING_PROPERTY_PREFIX + string, string1);
+        return put(STRING_PROPERTY_PREFIX + string, string1);
     }
 
-    public void setChar(String string, char c)
+    public Object setChar(String string, char c)
     {
-        checkPropertyName(string, CHAR_PROPERTY_PREFIX);
-
-        _properties.put(CHAR_PROPERTY_PREFIX + string, c);
+        return put(CHAR_PROPERTY_PREFIX + string, c);
     }
 
-    public void setBytes(String string, byte[] bytes)
+    public Object setBytes(String string, byte[] bytes)
     {
-        setBytes(string, bytes, 0, bytes.length);
+        return setBytes(string, bytes, 0, bytes.length);
     }
 
-    public void setBytes(String string, byte[] bytes, int start, int length)
+    public Object setBytes(String string, byte[] bytes, int start, int length)
     {
-        checkPropertyName(string, BYTES_PROPERTY_PREFIX);
-
-        _properties.put(BYTES_PROPERTY_PREFIX + string, sizeByteArray(bytes, start, length));
+        return put(BYTES_PROPERTY_PREFIX + string, sizeByteArray(bytes, start, length));
     }
 
     private byte[] sizeByteArray(byte[] bytes, int start, int length)
@@ -259,65 +338,65 @@
     }
 
 
-    public void setObject(String string, Object object)
+    public Object setObject(String string, Object object)
     {
         if (object instanceof Boolean)
         {
-            setBoolean(string, (Boolean) object);
+            return setBoolean(string, (Boolean) object);
         }
         else
         {
             if (object instanceof Byte)
             {
-                setByte(string, (Byte) object);
+                return setByte(string, (Byte) object);
             }
             else
             {
                 if (object instanceof Short)
                 {
-                    setShort(string, (Short) object);
+                    return setShort(string, (Short) object);
                 }
                 else
                 {
                     if (object instanceof Integer)
                     {
-                        setInteger(string, (Integer) object);
+                        return setInteger(string, (Integer) object);
                     }
                     else
                     {
                         if (object instanceof Long)
                         {
-                            setLong(string, (Long) object);
+                            return setLong(string, (Long) object);
                         }
                         else
                         {
                             if (object instanceof Float)
                             {
-                                setFloat(string, (Float) object);
+                                return setFloat(string, (Float) object);
                             }
                             else
                             {
                                 if (object instanceof Double)
                                 {
-                                    setDouble(string, (Double) object);
+                                    return setDouble(string, (Double) object);
                                 }
                                 else
                                 {
                                     if (object instanceof String)
                                     {
-                                        setString(string, (String) object);
+                                        return setString(string, (String) object);
                                     }
                                     else
                                     {
                                         if (object instanceof Character)
                                         {
-                                            setChar(string, (Character) object);
+                                            return setChar(string, (Character) object);
                                         }
                                         else
                                         {
                                             if (object instanceof byte[])
                                             {
-                                                setBytes(string, (byte[]) object);
+                                                return setBytes(string, (byte[]) object);
                                             }
                                         }
                                     }
@@ -328,8 +407,7 @@
                 }
             }
         }
-
-
+        return null;
     }
 
     // ***** Methods
@@ -344,12 +422,16 @@
         {
             String key = (String) keys.next();
 
-            names.add(key.substring(1));
+            names.add(key);
         }
 
         return names.elements();
     }
 
+    public boolean propertyExists(String propertyName)
+    {
+        return _propertyNamesTypeMap.containsKey(propertyName);
+    }
 
     public boolean itemExists(String string)
     {
@@ -367,7 +449,6 @@
         return false;
     }
 
-
     public String toString()
     {
         return valueOf(this);
@@ -390,35 +471,55 @@
             else
             {
                 buf.append('\n');
-                buf.append(propertyXML(propertyName, true));
 
-                if (propertyName.charAt(0) == BYTES_PROPERTY_PREFIX)
-                {
-                    //remove '>'
-                    buf.deleteCharAt(buf.length() - 1);
+                buf.append(valueAsXML(table._propertyNamesTypeMap.get(propertyName) + propertyName, entry.getValue()));
+            }
+        }
+        buf.append("\n");
+        buf.append(PROPERTY_FIELD_TABLE_CLOSE_XML);
 
-                    byte[] bytes = (byte[]) entry.getValue();
-                    buf.append(" length='").append(bytes.length).append("'>");
+        return buf.toString();
+    }
 
-                    buf.append(byteArrayToXML(propertyName.substring(1), bytes));
-                }
-                else
-                {
+    private static String valueAsXML(String name, Object value)
+    {
+        char propertyPrefix = name.charAt(0);
+        String propertyName = name.substring(1);
 
-                    buf.append(String.valueOf(entry.getValue()));
-                }
-                buf.append(propertyXML(propertyName, false));
 
-            }
+        StringBuffer buf = new StringBuffer();
+        // Start Tag
+        buf.append(propertyXML(name, true));
+
+        // Value
+        if (propertyPrefix == BYTES_PROPERTY_PREFIX)
+        {
+            //remove '>'
+            buf.deleteCharAt(buf.length() - 1);
+
+            byte[] bytes = (byte[]) value;
+            buf.append(" length='").append(bytes.length).append("'>");
+
+            buf.append(byteArrayToXML(propertyName, bytes));
+        }
+        else
+        {
+            buf.append(String.valueOf(value));
         }
-        buf.append("\n");
-        buf.append(PROPERTY_FIELD_TABLE_CLOSE_XML);
+
+        //End Tag
+        buf.append(propertyXML(name, false));
 
         return buf.toString();
     }
 
-    private void checkPropertyName(String propertyName, char propertyPrefix)
+    private Object checkPropertyName(String name)
     {
+        String propertyName = name.substring(1);
+        char propertyPrefix = name.charAt(0);
+
+        Object previous = null;
+
         if (propertyName == null)
         {
             throw new IllegalArgumentException("Property name must not be null");
@@ -432,15 +533,29 @@
 
         if (currentValue != null)
         {
-            _properties.remove(currentValue + propertyName);
+            previous = _properties.remove(currentValue + propertyName);
+
+            // If we are in effect deleting the value (see comment on null values being deleted
+            // below) then we also need to remove the name from the encoding length.
+            if (previous == null)
+            {
+                _encodedSize -= EncodingUtils.encodedShortStringLength(propertyName);
+            }
+
+            // FIXME: Should be able to short-cut this process if the old and new values are
+            // the same object and/or type and size...
+            _encodedSize -= getEncodingSize(currentValue + propertyName, previous);
         }
 
         _propertyNamesTypeMap.put(propertyName, "" + propertyPrefix);
+
+        return previous;
     }
 
-    private static String propertyXML(String propertyName, boolean start)
+    private static String propertyXML(String name, boolean start)
     {
-        char typeIdentifier = propertyName.charAt(0);
+        char propertyPrefix = name.charAt(0);
+        String propertyName = name.substring(1);
 
         StringBuffer buf = new StringBuffer();
 
@@ -453,8 +568,7 @@
             buf.append("</");
         }
 
-
-        switch (typeIdentifier)
+        switch (propertyPrefix)
         {
             case BOOLEAN_PROPERTY_PREFIX:
                 buf.append(BOOLEAN);
@@ -487,14 +601,13 @@
                 buf.append(CHAR);
                 break;
             default:
-                buf.append(UNKNOWN + " (identifier ").append(typeIdentifier).append(")");
+                buf.append(UNKNOWN + " (identifier ").append(propertyPrefix).append(")");
                 break;
         }
 
-
         if (start)
         {
-            buf.append(" name='").append(propertyName.substring(1)).append("'");
+            buf.append(" name='").append(propertyName).append("'");
         }
 
         buf.append(">");
@@ -519,8 +632,6 @@
 
     private void processBytesXMLLine(String xmlline)
     {
-        String type = xmlline.substring(1, xmlline.indexOf(" "));
-
         String propertyName = xmlline.substring(xmlline.indexOf('\'') + 1,
                                                 xmlline.indexOf('\'', xmlline.indexOf('\'') + 1));
         String value = xmlline.substring(xmlline.indexOf(">") + 1,
@@ -545,7 +656,6 @@
         {
             String token = tokenizer.nextToken();
 
-
             if (token.equals(PROPERTY_FIELD_TABLE_CLOSE_XML)
                 || token.equals(BYTES_CLOSE_XML))
             {
@@ -555,7 +665,6 @@
             if (token.equals(BYTES_CLOSE_XML))
             {
                 processing_bytes = false;
-
             }
 
             if (processing)
@@ -578,11 +687,9 @@
             {
                 processing = true;
             }
-
         }
     }
 
-
     private void processXMLLine(String xmlline)
     {
         // <<type> name='<property>'><value></<type>>
@@ -611,11 +718,39 @@
         }
         if (type.equals(BYTES))
         {
-            Integer length = Integer.parseInt(xmlline.substring(
-                    xmlline.lastIndexOf("=") + 2
-                    , xmlline.lastIndexOf("'")));
+            int headerEnd = xmlline.indexOf('>');
+            String bytesHeader = xmlline.substring(0, headerEnd);
+
+            //Extract length value
+            Integer length = Integer.parseInt(bytesHeader.substring(
+                    bytesHeader.lastIndexOf("=") + 2
+                    , bytesHeader.lastIndexOf("'")));
+
+
             byte[] bytes = new byte[length];
             setBytes(propertyName, bytes);
+
+            //Check if the line contains all the byte values
+            // This is needed as the XMLLine sent across the wire is the bytes value
+
+            int byteStart = xmlline.indexOf('<', headerEnd);
+
+            if (byteStart > 0)
+            {
+                while (!xmlline.startsWith(BYTES_CLOSE_XML, byteStart))
+                {
+                    //This should be the next byte line
+                    int bytePrefixEnd = xmlline.indexOf('>', byteStart) + 1;
+                    int byteEnd = xmlline.indexOf('>', bytePrefixEnd) + 1;
+
+                    String byteline = xmlline.substring(byteStart, byteEnd);
+
+                    processBytesXMLLine(byteline);
+
+                    byteStart = xmlline.indexOf('<', byteEnd);
+                }
+            }
+
         }
         if (type.equals(SHORT))
         {
@@ -651,6 +786,311 @@
         }
     }
 
+    // *************************  Byte Buffer Processing
+
+    public void writeToBuffer(ByteBuffer buffer)
+    {
+        final boolean debug = _logger.isDebugEnabled();
+
+        if (debug)
+        {
+            _logger.debug("FieldTable::writeToBuffer: Writing encoded size of " + _encodedSize + "...");
+        }
+
+        EncodingUtils.writeUnsignedInteger(buffer, _encodedSize);
+
+        putDataInBuffer(buffer);
+    }
+
+    public byte[] getDataAsBytes()
+    {
+        final ByteBuffer buffer = ByteBuffer.allocate((int) _encodedSize); // FIXME XXX: Is cast a problem?
+
+        putDataInBuffer(buffer);
+
+        final byte[] result = new byte[(int) _encodedSize];
+        buffer.flip();
+        buffer.get(result);
+        buffer.release();
+        return result;
+    }
+
+
+    public int size()
+    {
+        return _properties.size();
+    }
+
+    public boolean isEmpty()
+    {
+        return _properties.isEmpty();
+    }
+
+    public boolean containsKey(Object key)
+    {
+        return _properties.containsKey(key);
+    }
+
+    public boolean containsValue(Object value)
+    {
+        return _properties.containsValue(value);
+    }
+
+    public Object get(Object key)
+    {
+        return _properties.get(key);
+    }
+
+
+    public Object put(Object key, Object value)
+    {
+        return setObject(key.toString(), value);
+    }
+
+    protected Object put(String key, Object value)
+    {
+        Object previous = checkPropertyName(key);
+
+
+        String propertyName = key.substring(1);
+        char propertyPrefix = _propertyNamesTypeMap.get(propertyName).charAt(0);
+
+        if (value != null)
+        {
+            //Add the size of the propertyName
+            _encodedSize += EncodingUtils.encodedShortStringLength(propertyName);
+
+            // For now: Setting a null value is the equivalent of deleting it.
+            // This is ambiguous in the JMS spec and needs thrashing out and potentially
+            // testing against other implementations.
+
+            //Add the size of the content
+            _encodedSize += getEncodingSize(key, value);
+        }
+
+        _properties.put((String) propertyName, value);
+
+        return previous;
+    }
+
+    public Object remove(Object key)
+    {
+        if (key instanceof String)
+        {
+            throw new IllegalArgumentException("Property key be a string");
+        }
+
+        char propertyPrefix = ((String) key).charAt(0);
+
+        if (_properties.containsKey(key))
+        {
+            final Object value = _properties.remove(key);
+            // plus one for the type
+            _encodedSize -= EncodingUtils.encodedShortStringLength(((String) key));
+
+            // This check is, for now, unnecessary (we don't store null values).
+            if (value != null)
+            {
+                _encodedSize -= getEncodingSize(propertyPrefix + (String) key, value);
+            }
+
+            return value;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public void putAll(Map t)
+    {
+        Iterator it = t.keySet().iterator();
+
+        while (it.hasNext())
+        {
+            Object key = it.next();
+            put(key, t.get(key));
+        }
+    }
+
+    public void clear()
+    {
+        _properties.clear();
+        _propertyNamesTypeMap.clear();
+    }
+
+    public Set keySet()
+    {
+        return _properties.keySet();
+    }
+
+    public Collection values()
+    {
+        return _properties.values();
+    }
+
+    public Set entrySet()
+    {
+        return _properties.entrySet();
+    }
+
+    public long getEncodedSize()
+    {
+        return _encodedSize;
+    }
 
-}
 
+    private void putDataInBuffer(ByteBuffer buffer)
+    {
+        final Iterator it = _properties.entrySet().iterator();
+
+        //If there are values then write out the encoded Size... could check _encodedSize != 0
+        // write out the total length, which we have kept up to date as data is added
+
+
+        while (it.hasNext())
+        {
+            Map.Entry me = (Map.Entry) it.next();
+            String propertyName = (String) me.getKey();
+
+            //The type value
+            char propertyPrefix = _propertyNamesTypeMap.get(propertyName).charAt(0);
+            //The actual param name skipping type
+
+            EncodingUtils.writeShortStringBytes(buffer, propertyName);
+            Object value = me.getValue();
+
+            switch (propertyPrefix)
+            {
+
+                case STRING_PROPERTY_PREFIX:
+                    // TODO: look at using proper charset encoder
+                    buffer.put((byte) STRING_PROPERTY_PREFIX);
+                    EncodingUtils.writeLongStringBytes(buffer, (String) value);
+                    break;
+
+                case AMQP_UNSIGNEDINT_PROPERTY_PREFIX:
+                case LONG_PROPERTY_PREFIX:
+                case INT_PROPERTY_PREFIX:
+                case BOOLEAN_PROPERTY_PREFIX:
+                case BYTE_PROPERTY_PREFIX:
+                case SHORT_PROPERTY_PREFIX:
+                case FLOAT_PROPERTY_PREFIX:
+                case DOUBLE_PROPERTY_PREFIX:
+                case CHAR_PROPERTY_PREFIX:
+                case BYTES_PROPERTY_PREFIX:
+                case XML_PROPERTY_PREFIX:
+                    // Encode as XML
+                    buffer.put((byte) XML_PROPERTY_PREFIX);
+                    EncodingUtils.writeLongStringBytes(buffer, valueAsXML(propertyPrefix + propertyName, value));
+                    break;
+                default:
+                {
+
+                    // Should never get here
+                    throw new IllegalArgumentException("Key '" + propertyName + "': Unsupported type in field table, type: " + ((value == null) ? "null-object" : value.getClass()));
+                }
+            }
+        }
+    }
+
+
+    public void setFromBuffer(ByteBuffer buffer, long length) throws AMQFrameDecodingException
+    {
+        final boolean debug = _logger.isDebugEnabled();
+
+        int sizeRead = 0;
+        while (sizeRead < length)
+        {
+            int sizeRemaining = buffer.remaining();
+            final String key = EncodingUtils.readShortString(buffer);
+            // TODO: use proper charset decoder
+            byte iType = buffer.get();
+            final char type = (char) iType;
+            Object value = null;
+
+            switch (type)
+            {
+                case STRING_PROPERTY_PREFIX:
+                    value = EncodingUtils.readLongString(buffer);
+                    break;
+                case LONG_PROPERTY_PREFIX:
+                case INT_PROPERTY_PREFIX:
+                case BOOLEAN_PROPERTY_PREFIX:
+                case BYTE_PROPERTY_PREFIX:
+                case SHORT_PROPERTY_PREFIX:
+                case FLOAT_PROPERTY_PREFIX:
+                case DOUBLE_PROPERTY_PREFIX:
+                case CHAR_PROPERTY_PREFIX:
+                case BYTES_PROPERTY_PREFIX:
+                case XML_PROPERTY_PREFIX:
+                    processXMLLine(EncodingUtils.readLongString(buffer));
+                    break;
+                default:
+                    String msg = "Field '" + key + "' - unsupported field table type: " + type + ".";
+                    //some extra debug information...
+                    msg += " (" + iType + "), length=" + length + ", sizeRead=" + sizeRead + ", sizeRemaining=" + sizeRemaining;
+                    throw new AMQFrameDecodingException(msg);
+            }
+
+            sizeRead += (sizeRemaining - buffer.remaining());
+
+            if (debug)
+            {
+                _logger.debug("FieldTable::PropFieldTable(buffer," + length + "): Read type '" + type + "', key '" + key + "', value '" + value + "' (now read " + sizeRead + " of " + length + " encoded bytes)...");
+            }
+
+            if (type != XML_PROPERTY_PREFIX)
+            {
+                setObject(key, value);
+            }
+        }
+
+        if (debug)
+        {
+            _logger.debug("FieldTable::FieldTable(buffer," + length + "): Done.");
+        }
+    }
+
+
+    /**
+     * @param name  the property name with type prefix
+     * @param value the property value
+     * @return integer
+     */
+    private static int getEncodingSize(String name, Object value)
+    {
+        int encodingSize;
+
+        char propertyPrefix = name.charAt(0);
+
+        switch (propertyPrefix)
+        {
+            // the extra byte if for the type indicator that is written out
+            case STRING_PROPERTY_PREFIX:
+                encodingSize = 1 + EncodingUtils.encodedLongStringLength((String) value);
+                break;
+            case LONG_PROPERTY_PREFIX:
+            case INT_PROPERTY_PREFIX:
+            case BOOLEAN_PROPERTY_PREFIX:
+            case BYTE_PROPERTY_PREFIX:
+            case SHORT_PROPERTY_PREFIX:
+            case FLOAT_PROPERTY_PREFIX:
+            case DOUBLE_PROPERTY_PREFIX:
+            case CHAR_PROPERTY_PREFIX:
+            case BYTES_PROPERTY_PREFIX:
+            case XML_PROPERTY_PREFIX:
+                encodingSize = 1 + EncodingUtils.encodedLongStringLength(valueAsXML(name, value));
+                break;
+            default:
+                //encodingSize = 1 + EncodingUtils.encodedLongStringLength(String.valueOf(value));
+                //  We are using XML String encoding
+                throw new IllegalArgumentException("Unsupported type in field table: " + value.getClass());
+        }
+
+// the extra byte for the type indicator is calculated in the name
+        return encodingSize;
+    }
+
+
+}

Modified: incubator/qpid/trunk/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java?view=diff&rev=482733&r1=482732&r2=482733
==============================================================================
--- incubator/qpid/trunk/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java (original)
+++ incubator/qpid/trunk/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java Tue Dec  5 10:37:18 2006
@@ -25,6 +25,10 @@
 
 import java.util.Enumeration;
 
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.ByteBufferProxy;
+import org.apache.mina.common.support.BaseByteBuffer;
+
 public class PropertyFieldTableTest extends TestCase
 {
 
@@ -206,7 +210,7 @@
 
         PropertyFieldTable table2 = new PropertyFieldTable(table1XML);
 
-        Assert.assertEquals(table1XML, table2.toString());        
+        Assert.assertEquals(table1XML, table2.toString());
     }
 
     public void testKeyEnumeration()
@@ -271,6 +275,117 @@
         Assert.assertEquals(Integer.MAX_VALUE, table.getObject("object-int"));
         Assert.assertEquals(Long.MAX_VALUE, table.getObject("object-long"));
         Assert.assertEquals(Short.MAX_VALUE, table.getObject("object-short"));
+    }
+
+
+    public void testwriteBuffer()
+    {
+        byte[] bytes = {99, 98, 97, 96, 95};
+
+        PropertyFieldTable table = new PropertyFieldTable();
+        table.setBoolean("bool", true);
+        table.setByte("byte", Byte.MAX_VALUE);
+
+        table.setBytes("bytes", bytes);
+        table.setChar("char", 'c');
+        table.setDouble("double", Double.MAX_VALUE);
+        table.setFloat("float", Float.MAX_VALUE);
+        table.setInteger("int", Integer.MAX_VALUE);
+        table.setLong("long", Long.MAX_VALUE);
+        table.setShort("short", Short.MAX_VALUE);
+
+
+        final ByteBuffer buffer = ByteBuffer.allocate((int) table.getEncodedSize()); // FIXME XXX: Is cast a problem?
+
+        table.writeToBuffer(buffer);
+
+        buffer.flip();
+
+        long length = buffer.getUnsignedInt();
+
+        try
+        {
+            PropertyFieldTable table2 = new PropertyFieldTable(buffer, length);
+
+            Assert.assertEquals((Boolean) true, table2.getBoolean("bool"));
+            Assert.assertEquals((Byte) Byte.MAX_VALUE, table2.getByte("byte"));
+            assertBytesEqual(bytes, table2.getBytes("bytes"));
+            Assert.assertEquals((Character) 'c', table2.getCharacter("char"));
+            Assert.assertEquals(Double.MAX_VALUE, table2.getDouble("double"));
+            Assert.assertEquals(Float.MAX_VALUE, table2.getFloat("float"));
+            Assert.assertEquals((Integer) Integer.MAX_VALUE, table2.getInteger("int"));
+            Assert.assertEquals((Long) Long.MAX_VALUE, table2.getLong("long"));
+            Assert.assertEquals((Short) Short.MAX_VALUE, table2.getShort("short"));
+        }
+        catch (AMQFrameDecodingException e)
+        {
+            e.printStackTrace();
+            fail("PFT should be instantiated from bytes." + e.getCause());
+        }
+    }
+
+    public void testEncodingSize()
+    {
+        FieldTable result = FieldTableFactory.newFieldTable();
+        int size = 0;
+        result.put("one", 1L);
+        // size is 1(size) + bytes for short string
+        size = 1 + 3; // 1 + key length
+        // or size is 1(the type) + number of bytes (4bytes worth) + bytes
+        size += 1 + 4;                 // 1 + 4 + value length
+        size += "<long name='one'>1</long>".length(); // this is the xml encoding for a long.
+        assertEquals(size, result.getEncodedSize());
+
+        result.put("two", 2L);
+        size += 1 + 3; // 1 + key length
+        size += 1 + 4;                 // 1 + 4 + value length
+        size += "<long name='two'>2</long>".length(); // this is the xml encoding for a long.
+        assertEquals(size, result.getEncodedSize());
+
+        result.put("three", 3L);
+        size += 1 + 5; // 1 + key length
+        size += 1 + 4;                 // 1 + 4 + value length
+        size += "<long name='three'>3</long>".length(); // this is the xml encoding for a long.
+        assertEquals(size, result.getEncodedSize());
+
+        result.put("four", 4L);
+        size += 1 + 4; // 1 + key length
+        size += 1 + 4;                 // 1 + 4 + value length
+        size += "<long name='four'>4</long>".length(); // this is the xml encoding for a long.
+        assertEquals(size, result.getEncodedSize());
+
+        result.put("five", 5L);
+        size += 1 + 4; // 1 + key length
+        size += 1 + 4;                 // 1 + 4 + value length
+        size += "<long name='five'>5</long>".length(); // this is the xml encoding for a long.
+        assertEquals(size, result.getEncodedSize());
+
+        //fixme should perhaps be expanded to incorporate all types.
+
+        final ByteBuffer buffer = ByteBuffer.allocate((int) result.getEncodedSize()); // FIXME XXX: Is cast a problem?
+
+        result.writeToBuffer(buffer);
+
+        buffer.flip();
+
+        long length = buffer.getUnsignedInt();
+
+        try
+        {
+            PropertyFieldTable table2 = new PropertyFieldTable(buffer, length);
+
+            Assert.assertEquals((Long) 1L, table2.getLong("one"));
+            Assert.assertEquals((Long) 2L, table2.getLong("two"));
+            Assert.assertEquals((Long) 3L, table2.getLong("three"));
+            Assert.assertEquals((Long) 4L, table2.getLong("four"));
+            Assert.assertEquals((Long) 5L, table2.getLong("five"));
+        }
+        catch (AMQFrameDecodingException e)
+        {
+            e.printStackTrace();
+            fail("PFT should be instantiated from bytes." + e.getCause());
+        }
+
     }
 
     private void assertBytesEqual(byte[] expected, byte[] actual)

Modified: incubator/qpid/trunk/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTest.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTest.java?view=diff&rev=482733&r1=482732&r2=482733
==============================================================================
--- incubator/qpid/trunk/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTest.java (original)
+++ incubator/qpid/trunk/qpid/java/systests/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTest.java Tue Dec  5 10:37:18 2006
@@ -20,26 +20,25 @@
  */
 package org.apache.qpid.server.exchange;
 
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.NoConsumersException;
-import org.apache.qpid.server.queue.AMQMessage;
-import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.SkeletonMessageStore;
-import org.apache.qpid.server.registry.ApplicationRegistry;
+import junit.framework.TestCase;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
 import org.apache.qpid.framing.BasicPublishBody;
-import org.apache.qpid.framing.ContentHeaderBody;
 import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
 import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.BasicContentHeaderProperties;
-import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.FieldTableFactory;
+import org.apache.qpid.server.queue.AMQMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.SkeletonMessageStore;
 
-import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Set;
 import java.util.HashSet;
-
-import junit.framework.TestCase;
+import java.util.List;
+import java.util.Set;
 
 public class AbstractHeadersExchangeTest extends TestCase
 {
@@ -105,7 +104,7 @@
 
     static FieldTable getHeaders(String... entries)
     {
-        FieldTable headers = new FieldTable();
+        FieldTable headers = FieldTableFactory.newFieldTable();
         for (String s : entries)
         {
             String[] parts = s.split("=", 2);