You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2018/10/04 13:04:10 UTC

[2/2] qpid-broker-j git commit: QPID-8245: [Broker-J][AMQP 0-8..0-91] Make FieldTable properties immutable and decode them on demand

QPID-8245: [Broker-J][AMQP 0-8..0-91] Make FieldTable properties immutable and decode them on demand


Project: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/commit/ae14be5d
Tree: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/tree/ae14be5d
Diff: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/diff/ae14be5d

Branch: refs/heads/master
Commit: ae14be5dffcf89b84c7d3eef5346d3b3d3ca75fc
Parents: bab681e
Author: Alex Rudyy <or...@apache.org>
Authored: Thu Oct 4 12:32:00 2018 +0100
Committer: Alex Rudyy <or...@apache.org>
Committed: Thu Oct 4 14:03:37 2018 +0100

----------------------------------------------------------------------
 .../store/berkeleydb/FieldTableEncoding.java    |    3 +-
 .../berkeleydb/upgrade/UpgradeFrom4To5.java     |   16 +-
 .../berkeleydb/upgrade/UpgradeFrom5To6.java     |    9 +-
 .../store/berkeleydb/BDBMessageStoreTest.java   |    4 +-
 .../server/protocol/v0_8/AMQShortString.java    |    2 +-
 .../qpid/server/protocol/v0_8/AMQType.java      |  129 +-
 .../server/protocol/v0_8/AMQTypedValue.java     |    6 +-
 .../server/protocol/v0_8/EncodingUtils.java     |   21 +-
 .../qpid/server/protocol/v0_8/FieldArray.java   |   10 +
 .../qpid/server/protocol/v0_8/FieldTable.java   | 1190 +++---------------
 .../server/protocol/v0_8/FieldTableFactory.java |   16 +-
 .../server/protocol/v0_8/FieldTableTest.java    |  847 +++----------
 .../protocol/v0_8/AMQPConnection_0_8Impl.java   |   17 +-
 .../server/protocol/v0_8/MessageMetaData.java   |    4 +-
 .../transport/BasicContentHeaderProperties.java |   36 +-
 .../server/protocol/v0_8/AMQDecoderTest.java    |   11 +-
 .../protocol/v0_8/AMQPConnection_0_8Test.java   |    2 +-
 .../BasicContentHeaderPropertiesTest.java       |   10 +-
 .../MessageConverter_0_10_to_0_8.java           |   22 +-
 .../v0_8_v1_0/MessageConverter_1_0_to_v0_8.java |    3 +-
 20 files changed, 641 insertions(+), 1717 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/FieldTableEncoding.java
----------------------------------------------------------------------
diff --git a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/FieldTableEncoding.java b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/FieldTableEncoding.java
index a084e93..8dddbe8 100644
--- a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/FieldTableEncoding.java
+++ b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/FieldTableEncoding.java
@@ -26,6 +26,7 @@ import com.sleepycat.je.DatabaseException;
 
 import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
 import org.apache.qpid.server.protocol.v0_8.FieldTable;
+import org.apache.qpid.server.protocol.v0_8.FieldTableFactory;
 import org.apache.qpid.server.store.berkeleydb.tuple.ByteBufferBinding;
 
 import java.nio.ByteBuffer;
@@ -49,7 +50,7 @@ public class FieldTableEncoding
 
             ByteBuffer buf = ByteBufferBinding.getInstance().readByteBuffer(tupleInput, (int) length);
 
-            return new FieldTable(QpidByteBuffer.wrap(buf));
+            return FieldTableFactory.createFieldTable(QpidByteBuffer.wrap(buf));
 
         }
 

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4To5.java
----------------------------------------------------------------------
diff --git a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4To5.java b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4To5.java
index 8935d37..f7c9b87 100644
--- a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4To5.java
+++ b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom4To5.java
@@ -23,8 +23,11 @@ package org.apache.qpid.server.store.berkeleydb.upgrade;
 import java.nio.ByteBuffer;
 import java.text.MessageFormat;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import com.sleepycat.bind.tuple.ByteBinding;
@@ -44,6 +47,7 @@ import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
 import org.apache.qpid.server.filter.AMQPFilterTypes;
 import org.apache.qpid.server.exchange.ExchangeDefaults;
 import org.apache.qpid.server.protocol.v0_8.AMQFrameDecodingException;
+import org.apache.qpid.server.protocol.v0_8.FieldTableFactory;
 import org.apache.qpid.server.protocol.v0_8.transport.AMQProtocolVersionException;
 import org.apache.qpid.server.protocol.v0_8.AMQShortString;
 import org.apache.qpid.server.protocol.v0_8.transport.ContentHeaderBody;
@@ -130,21 +134,23 @@ public class UpgradeFrom4To5 extends AbstractStoreUpgrade
                     if (potentialDurableSubs.contains(queueName)
                             && exchangeName.equals(AMQShortString.valueOf(ExchangeDefaults.TOPIC_EXCHANGE_NAME)))
                     {
-                        if (arguments == null)
+                        Map<String, Object> argumentsMap = new HashMap<>();
+                        if (arguments != null)
                         {
-                            arguments = new FieldTable();
+                            argumentsMap.putAll(FieldTable.convertToMap(arguments));
                         }
 
                         String selectorFilterKey = AMQPFilterTypes.JMS_SELECTOR.getValue();
-                        if (!arguments.containsKey(selectorFilterKey))
+                        if (!argumentsMap.containsKey(selectorFilterKey))
                         {
                             if (LOGGER.isDebugEnabled())
                             {
                                 LOGGER.info("adding the empty string (i.e. 'no selector') value for " + queueName
                                         + " and exchange " + exchangeName);
                             }
-                            arguments.setObject(selectorFilterKey, "");
+                            argumentsMap.put(selectorFilterKey, "");
                         }
+                        arguments = FieldTable.convertToFieldTable(argumentsMap);
                     }
                     addBindingToDatabase(bindingTuple, targetDatabase, transaction, queueName, exchangeName, routingKey,
                             arguments);
@@ -320,7 +326,7 @@ public class UpgradeFrom4To5 extends AbstractStoreUpgrade
                 binding.objectToEntry(record, newValue);
                 newQueueDatabase.put(transaction, key, newValue);
 
-                FieldTable emptyArguments = new FieldTable();
+                FieldTable emptyArguments = FieldTableFactory.createFieldTable(Collections.emptyMap());
                 addBindingToDatabase(bindingTuple, newBindingsDatabase, transaction, queueNameAMQ,
                         AMQShortString.valueOf(ExchangeDefaults.DIRECT_EXCHANGE_NAME), queueNameAMQ, emptyArguments);
 

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java
----------------------------------------------------------------------
diff --git a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java
index cde1bec..1d3a77c 100644
--- a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java
+++ b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/upgrade/UpgradeFrom5To6.java
@@ -60,6 +60,7 @@ import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.LifetimePolicy;
 import org.apache.qpid.server.model.Queue;
 import org.apache.qpid.server.model.UUIDGenerator;
+import org.apache.qpid.server.protocol.v0_8.FieldTableFactory;
 import org.apache.qpid.server.queue.QueueArgumentsConverter;
 import org.apache.qpid.server.store.StoreException;
 import org.apache.qpid.server.store.berkeleydb.AMQShortStringEncoding;
@@ -536,10 +537,10 @@ public class UpgradeFrom5To6 extends AbstractStoreUpgrade
         attributesMap.put(Queue.NAME, queueName);
         attributesMap.put(Queue.EXCLUSIVE, exclusive);
 
-        FieldTable argumentsCopy = new FieldTable();
+        HashMap<String, Object> argumentsCopy = new HashMap<>();
         if (arguments != null)
         {
-            argumentsCopy.addAll(arguments);
+            argumentsCopy.putAll(FieldTable.convertToMap(arguments));
         }
 
         if (moveNonExclusiveOwnerToDescription(owner, exclusive))
@@ -547,7 +548,7 @@ public class UpgradeFrom5To6 extends AbstractStoreUpgrade
             LOGGER.info("Non-exclusive owner " + owner + " for queue " + queueName + " moved to " + QueueArgumentsConverter.X_QPID_DESCRIPTION);
 
             attributesMap.put(Queue.OWNER, null);
-            argumentsCopy.setObject(QueueArgumentsConverter.X_QPID_DESCRIPTION, owner);
+            argumentsCopy.put(QueueArgumentsConverter.X_QPID_DESCRIPTION, owner);
         }
         else
         {
@@ -555,7 +556,7 @@ public class UpgradeFrom5To6 extends AbstractStoreUpgrade
         }
         if (!argumentsCopy.isEmpty())
         {
-            attributesMap.put(ARGUMENTS, FieldTable.convertToMap(argumentsCopy));
+            attributesMap.put(ARGUMENTS, argumentsCopy);
         }
         return attributesMap;
     }

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
----------------------------------------------------------------------
diff --git a/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java b/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
index 2226600..b45f6c2 100644
--- a/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
+++ b/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
@@ -30,12 +30,14 @@ import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 import java.io.File;
+import java.util.Collections;
 
 import org.junit.Test;
 
 import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.protocol.v0_8.AMQShortString;
+import org.apache.qpid.server.protocol.v0_8.FieldTableFactory;
 import org.apache.qpid.server.protocol.v0_8.MessageMetaData;
 import org.apache.qpid.server.protocol.v0_8.transport.BasicContentHeaderProperties;
 import org.apache.qpid.server.protocol.v0_8.transport.ContentHeaderBody;
@@ -96,7 +98,7 @@ public class BDBMessageStoreTest extends MessageStoreTestCase
         BasicContentHeaderProperties props = new BasicContentHeaderProperties();
         props.setDeliveryMode(Integer.valueOf(BasicContentHeaderProperties.PERSISTENT).byteValue());
         props.setContentType("text/html");
-        props.getHeaders().setString("Test", "MST");
+        props.setHeaders(FieldTableFactory.createFieldTable(Collections.singletonMap("Test", "MST")));
         return props;
     }
 

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQShortString.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQShortString.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQShortString.java
index 13af160..0f9db43 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQShortString.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQShortString.java
@@ -74,7 +74,7 @@ public final class AMQShortString implements Comparable<AMQShortString>
         _data = data;
     }
 
-    private static byte[] readAMQShortStringAsBytes(QpidByteBuffer buffer)
+    static byte[] readAMQShortStringAsBytes(QpidByteBuffer buffer)
     {
         int length = buffer.getUnsignedByte();
         if(length == 0)

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQType.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQType.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQType.java
index 29543b5..171f4d8 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQType.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQType.java
@@ -22,6 +22,7 @@ package org.apache.qpid.server.protocol.v0_8;
 
 import java.math.BigDecimal;
 import java.util.Collection;
+import java.util.Date;
 
 import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
 
@@ -64,6 +65,12 @@ public enum AMQType
         {
             return EncodingUtils.readLongString(buffer);
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            EncodingUtils.skipLongString(buffer);
+        }
     },
 
     INTEGER('i')
@@ -115,6 +122,12 @@ public enum AMQType
         {
             return buffer.getUnsignedInt();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Integer.BYTES);
+        }
     },
 
     DECIMAL('D')
@@ -165,6 +178,12 @@ public enum AMQType
 
             return bd.setScale(places);
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Integer.BYTES + Byte.BYTES);
+        }
     },
 
     TIMESTAMP('T')
@@ -180,7 +199,11 @@ public enum AMQType
         {
             if (value instanceof Long)
             {
-                return (Long) value;
+                return value;
+            }
+            else if (value instanceof Date)
+            {
+                return ((Date) value).getTime();
             }
             else
             {
@@ -200,6 +223,12 @@ public enum AMQType
         {
             return buffer.getLong();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Long.BYTES);
+        }
     },
 
     /**
@@ -285,6 +314,12 @@ public enum AMQType
                 throw new IllegalArgumentException("Unable to read field table from buffer.", e);
             }
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            EncodingUtils.skipFieldTable(buffer);
+        }
     },
     /**
      * Implements the field table type. The native value of a field table type will be an instance of
@@ -346,6 +381,12 @@ public enum AMQType
                     return FieldArray.readFromBuffer(buffer);
 
                 }
+
+                @Override
+                void skip(final QpidByteBuffer buffer)
+                {
+                    FieldArray.skipFieldArray(buffer);
+                }
             },
     VOID('V')
     {
@@ -378,6 +419,12 @@ public enum AMQType
         {
             return null;
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            // no-op
+        }
     },
 
     BINARY('x')
@@ -413,6 +460,12 @@ public enum AMQType
         {
             return EncodingUtils.readLongstr(buffer);
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            EncodingUtils.skipLongString(buffer);
+        }
     },
 
     ASCII_STRING('c')
@@ -447,6 +500,12 @@ public enum AMQType
         {
             return EncodingUtils.readLongString(buffer);
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            EncodingUtils.skipLongString(buffer);
+        }
     },
 
     WIDE_STRING('C')
@@ -482,6 +541,12 @@ public enum AMQType
         {
             return EncodingUtils.readLongString(buffer);
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            EncodingUtils.skipLongString(buffer);
+        }
     },
 
     BOOLEAN('t')
@@ -521,6 +586,12 @@ public enum AMQType
         {
             return buffer.get() == 1;
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Byte.BYTES);
+        }
     },
 
     ASCII_CHARACTER('k')
@@ -561,6 +632,12 @@ public enum AMQType
         {
             return (char) buffer.get();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Byte.BYTES);
+        }
     },
 
     BYTE('b')
@@ -600,6 +677,12 @@ public enum AMQType
         {
             return buffer.get();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Byte.BYTES);
+        }
     },
 
     UNSIGNED_BYTE('B')
@@ -647,6 +730,12 @@ public enum AMQType
                 {
                     return buffer.getUnsignedByte();
                 }
+
+                @Override
+                void skip(final QpidByteBuffer buffer)
+                {
+                    buffer.position(buffer.position() + Byte.BYTES);
+                }
     },
 
     SHORT('s')
@@ -690,6 +779,12 @@ public enum AMQType
         {
             return buffer.getShort();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Short.BYTES);
+        }
     },
 
     UNSIGNED_SHORT('u')
@@ -737,6 +832,12 @@ public enum AMQType
         {
             return buffer.getUnsignedShort();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Short.BYTES);
+        }
     },
 
     INT('I')
@@ -782,6 +883,12 @@ public enum AMQType
         {
             return buffer.getInt();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Integer.BYTES);
+        }
     },
 
     LONG('l')
@@ -833,6 +940,12 @@ public enum AMQType
         {
             return buffer.getLong();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Long.BYTES);
+        }
     },
 
     FLOAT('f')
@@ -872,6 +985,12 @@ public enum AMQType
         {
             return buffer.getFloat();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Float.BYTES);
+        }
     },
 
     DOUBLE('d')
@@ -915,6 +1034,12 @@ public enum AMQType
         {
             return buffer.getDouble();
         }
+
+        @Override
+        void skip(final QpidByteBuffer buffer)
+        {
+            buffer.position(buffer.position() + Double.BYTES);
+        }
     };
 
     /** Holds the defined one byte identifier for the type. */
@@ -987,4 +1112,6 @@ public enum AMQType
      * @return An instance of the type.
      */
     abstract Object readValueFromBuffer(QpidByteBuffer buffer);
+
+    abstract void skip(QpidByteBuffer buffer);
 }

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQTypedValue.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQTypedValue.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQTypedValue.java
index 89fdc8d..6836c3e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQTypedValue.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQTypedValue.java
@@ -282,6 +282,10 @@ public abstract class AMQTypedValue
         {
             return AMQType.ASCII_CHARACTER.asTypedValue(val);
         }
+        else if (klass == Short.class)
+        {
+            return AMQType.SHORT.asTypedValue(val);
+        }
         else if(klass == Integer.class)
         {
             return AMQType.INT.asTypedValue(val);
@@ -322,7 +326,7 @@ public abstract class AMQTypedValue
         {
             return AMQType.FIELD_TABLE.asTypedValue(FieldTable.convertToFieldTable((Map<String,Object>)val));
         }
-        else if(klass == FieldTable.class)
+        else if(val instanceof FieldTable)
         {
             return AMQType.FIELD_TABLE.asTypedValue(val);
         }

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/EncodingUtils.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/EncodingUtils.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/EncodingUtils.java
index 653d12c..5039552 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/EncodingUtils.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/EncodingUtils.java
@@ -213,7 +213,16 @@ public class EncodingUtils
         }
         else
         {
-            return new FieldTable(input, (int) length);
+            return FieldTableFactory.createFieldTable(input, (int) length);
+        }
+    }
+
+    public static void skipFieldTable(QpidByteBuffer buffer)
+    {
+        long length = buffer.getUnsignedInt();
+        if (length > 0)
+        {
+            buffer.position(buffer.position() + (int)length);
         }
     }
 
@@ -234,6 +243,16 @@ public class EncodingUtils
         }
     }
 
+
+    public static void skipLongString(final QpidByteBuffer buffer)
+    {
+        long length = buffer.getUnsignedInt();
+        if (length > 0)
+        {
+            buffer.position(buffer.position() + (int)length);
+        }
+    }
+
     public static byte[] readLongstr(QpidByteBuffer buffer)
     {
         long length = ((long)(buffer.getInt())) & 0xFFFFFFFFL;

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldArray.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldArray.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldArray.java
index 9e5222b..8b55a5c 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldArray.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldArray.java
@@ -127,4 +127,14 @@ public class FieldArray<T> extends AbstractCollection<T>
         }
         return new FieldArray<>(result);
     }
+
+    public static void skipFieldArray(final QpidByteBuffer buffer)
+    {
+        int size = buffer.getInt();
+        if (size > 0)
+        {
+            buffer.position(buffer.position() + size);
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTable.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTable.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTable.java
index 561a24e..1f5e8cb 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTable.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTable.java
@@ -21,18 +21,17 @@
 package org.apache.qpid.server.protocol.v0_8;
 
 import java.math.BigDecimal;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
-import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
-import java.util.stream.Collectors;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,820 +43,205 @@ public class FieldTable
     private static final Logger LOGGER = LoggerFactory.getLogger(FieldTable.class);
     private static final String STRICT_AMQP_NAME = "STRICT_AMQP";
     private static final boolean STRICT_AMQP = Boolean.valueOf(System.getProperty(STRICT_AMQP_NAME, "false"));
+    private static final AMQTypedValue NOT_PRESENT = AMQType.VOID.asTypedValue(null);
 
-    private QpidByteBuffer _encodedForm;
-    private Map<String, AMQTypedValue> _properties = null;
-    private long _encodedSize;
-    private static final int INITIAL_HASHMAP_CAPACITY = 16;
-    private final boolean _strictAMQP;
-
-    public FieldTable()
-    {
-        this(STRICT_AMQP);
-    }
-
-
-    public FieldTable(boolean strictAMQP)
-    {
-        super();
-        _strictAMQP = strictAMQP;
-    }
-
-    public FieldTable(FieldTable other)
-    {
-        _encodedForm = other._encodedForm;
-        _encodedSize = other._encodedSize;
-        _strictAMQP = other._strictAMQP;
-        if(other._properties != null)
-        {
-            _properties = new LinkedHashMap<>(other._properties);
-        }
-    }
-
-    public FieldTable(QpidByteBuffer input, int len)
-    {
-        this();
-        _encodedForm = input.view(0,len);
-        input.position(input.position()+len);
-        _encodedSize = len;
-    }
-
-    public FieldTable(QpidByteBuffer buffer)
-    {
-        this();
-        _encodedForm = buffer.duplicate();
-        _encodedSize = buffer.remaining();
-    }
-
-    public synchronized boolean isClean()
-    {
-        return _encodedForm != null;
-    }
-
-    @Deprecated
-    public AMQTypedValue getProperty(AMQShortString string)
-    {
-        return getProperty(AMQShortString.toString(string));
-    }
-
-    private AMQTypedValue getProperty(String string)
-    {
-        checkPropertyName(string);
-
-        synchronized (this)
-        {
-            if (_properties == null)
-            {
-                if (_encodedForm == null)
-                {
-                    return null;
-                }
-                else
-                {
-                    populateFromBuffer();
-                }
-            }
-        }
-
-        if (_properties == null)
-        {
-            return null;
-        }
-        else
-        {
-            return _properties.get(string);
-        }
-    }
-
-    private void populateFromBuffer()
-    {
-        if (_encodedSize > 0)
-        {
-            _properties = new LinkedHashMap<>(INITIAL_HASHMAP_CAPACITY);
-
-            _encodedForm.mark();
-            try
-            {
-                do
-                {
-                    final String key = AMQShortString.readAMQShortStringAsString(_encodedForm);
-                    AMQTypedValue value = AMQTypedValue.readFromBuffer(_encodedForm);
-                    _properties.put(key, value);
-                }
-                while (_encodedForm.hasRemaining());
-            }
-            finally
-            {
-                _encodedForm.reset();
-            }
-        }
-    }
-
-    private AMQTypedValue setProperty(String key, AMQTypedValue val)
-    {
-        checkPropertyName(key);
-
-        synchronized (this)
-        {
-            initMapIfNecessary();
-            if (_properties.containsKey(key))
-            {
-                _encodedForm = null;
-
-                if (val == null)
-                {
-                    return removeKey(key);
-                }
-            }
-            else if ((_encodedForm != null) && (val != null))
-            {
-                // We have updated data to store in the buffer
-                // So clear the _encodedForm to allow it to be rebuilt later
-                // this is safer than simply appending to any existing buffer.
-                _encodedForm = null;
-            }
-            else if (val == null)
-            {
-                return null;
-            }
-        }
-
-        AMQTypedValue oldVal = _properties.put(key, val);
-        if (oldVal != null)
-        {
-            _encodedSize -= oldVal.getEncodingSize();
-        }
-        else
-        {
-            _encodedSize += EncodingUtils.encodedShortStringLength(key) + 1;
-        }
-
-        _encodedSize += val.getEncodingSize();
-
-        return oldVal;
-    }
-
-    private void initMapIfNecessary()
-    {
-        synchronized (this)
-        {
-            if (_properties == null)
-            {
-                if ((_encodedForm == null) || (_encodedSize == 0))
-                {
-                    _properties = new LinkedHashMap<>();
-                }
-                else
-                {
-                    populateFromBuffer();
-                }
-            }
-
-        }
-    }
-
-    @Deprecated
-    public Boolean getBoolean(AMQShortString string)
-    {
-        return getBoolean(AMQShortString.toString(string));
-    }
-
-    public Boolean getBoolean(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.BOOLEAN))
-        {
-            return (Boolean) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public Byte getByte(AMQShortString string)
-    {
-        return getByte(AMQShortString.toString(string));
-    }
-
-    public Byte getByte(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.BYTE))
-        {
-            return (Byte) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
+    public static final FieldTable EMPTY = FieldTable.convertToFieldTable(Collections.emptyMap());
 
-    @Deprecated
-    public Short getShort(AMQShortString string)
-    {
-        return getShort(AMQShortString.toString(string));
-    }
-
-    public Short getShort(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.SHORT))
-        {
-            return (Short) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public Integer getInteger(AMQShortString string)
-    {
-        return getInteger(AMQShortString.toString(string));
-    }
-
-    public Integer getInteger(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.INT))
-        {
-            return (Integer) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public Long getLong(AMQShortString string)
-    {
-        return getLong(AMQShortString.toString(string));
-    }
-
-    public Long getLong(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.LONG))
-        {
-            return (Long) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public Float getFloat(AMQShortString string)
-    {
-        return getFloat(AMQShortString.toString(string));
-    }
-
-    public Float getFloat(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.FLOAT))
-        {
-            return (Float) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public Double getDouble(AMQShortString string)
-    {
-        return getDouble(AMQShortString.toString(string));
-    }
-
-    public Double getDouble(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.DOUBLE))
-        {
-            return (Double) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public String getString(AMQShortString string)
-    {
-        return getString(AMQShortString.toString(string));
-    }
-
-    public String getString(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && ((value.getType() == AMQType.WIDE_STRING) || (value.getType() == AMQType.ASCII_STRING)))
-        {
-            return (String) value.getValue();
-        }
-        else if ((value != null) && (value.getValue() != null) && !(value.getValue() instanceof byte[]))
-        {
-            return String.valueOf(value.getValue());
-        }
-        else
-        {
-            return null;
-        }
-
-    }
-
-    @Deprecated
-    public Character getCharacter(AMQShortString string)
-    {
-        return getCharacter(AMQShortString.toString(string));
-    }
-
-    public Character getCharacter(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.ASCII_CHARACTER))
-        {
-            return (Character) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public byte[] getBytes(AMQShortString string)
-    {
-        return getBytes(AMQShortString.toString(string));
-    }
-
-    public byte[] getBytes(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if ((value != null) && (value.getType() == AMQType.BINARY))
-        {
-            return (byte[]) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    /**
-     * 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.
-     */
-    @Deprecated
-    public FieldTable getFieldTable(AMQShortString string)
-    {
-        return getFieldTable(AMQShortString.toString(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(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-
-        if ((value != null) && (value.getType() == AMQType.FIELD_TABLE))
-        {
-            return (FieldTable) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public Object getObject(AMQShortString string)
-    {
-        return getObject(AMQShortString.toString(string));
-    }
-
-    public Object getObject(String string)
-    {
-        AMQTypedValue value = getProperty(string);
-        if (value != null)
-        {
-            return value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-
-    }
-
-    @Deprecated
-    public Long getTimestamp(AMQShortString name)
-    {
-        return getTimestamp(AMQShortString.toString(name));
-    }
-
-    public Long getTimestamp(String name)
-    {
-        AMQTypedValue value = getProperty(name);
-        if ((value != null) && (value.getType() == AMQType.TIMESTAMP))
-        {
-            return (Long) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    @Deprecated
-    public BigDecimal getDecimal(AMQShortString propertyName)
-    {
-        return getDecimal(AMQShortString.toString(propertyName));
-    }
-
-    public BigDecimal getDecimal(String propertyName)
-    {
-        AMQTypedValue value = getProperty(propertyName);
-        if ((value != null) && (value.getType() == AMQType.DECIMAL))
-        {
-            return (BigDecimal) value.getValue();
-        }
-        else
-        {
-            return null;
-        }
-    }
-
-    // ************  Setters
-
-    @Deprecated
-    public Object setBoolean(AMQShortString string, Boolean b)
-    {
-        return setBoolean(AMQShortString.toString(string), b);
-    }
-
-    public Object setBoolean(String string, Boolean b)
-    {
-        return setProperty(string, AMQType.BOOLEAN.asTypedValue(b));
-    }
-
-    @Deprecated
-    public Object setByte(AMQShortString string, Byte b)
-    {
-        return setByte(AMQShortString.toString(string), b);
-    }
-
-    public Object setByte(String string, Byte b)
-    {
-        return setProperty(string, AMQType.BYTE.asTypedValue(b));
-    }
-
-    @Deprecated
-    public Object setShort(AMQShortString string, Short i)
-    {
-        return setShort(AMQShortString.toString(string), i);
-    }
-
-    public Object setShort(String string, Short i)
-    {
-        return setProperty(string, AMQType.SHORT.asTypedValue(i));
-    }
-
-    @Deprecated
-    public Object setInteger(AMQShortString string, int i)
-    {
-        return setInteger(AMQShortString.toString(string), i);
-    }
-
-    public Object setInteger(String string, int i)
-    {
-        return setProperty(string, AMQTypedValue.createAMQTypedValue(i));
-    }
-
-    @Deprecated
-    public Object setLong(AMQShortString string, long l)
-    {
-        return setLong(AMQShortString.toString(string), l);
-    }
-
-    public Object setLong(String string, long l)
-    {
-        return setProperty(string, AMQTypedValue.createAMQTypedValue(l));
-    }
-
-    @Deprecated
-    public Object setFloat(AMQShortString string, Float v)
-    {
-        return setFloat(AMQShortString.toString(string), v);
-    }
-
-    public Object setFloat(String string, Float f)
-    {
-        return setProperty(string, AMQType.FLOAT.asTypedValue(f));
-    }
-
-    @Deprecated
-    public Object setDouble(AMQShortString string, Double d)
-    {
-        return setDouble(AMQShortString.toString(string), d);
-    }
-
-    public Object setDouble(String string, Double v)
-    {
-        return setProperty(string, AMQType.DOUBLE.asTypedValue(v));
-    }
+    private QpidByteBuffer _encodedForm;
+    private boolean _decoded;
+    private final Map<String, AMQTypedValue> _properties;
+    private final long _encodedSize;
+    private final boolean _strictAMQP;
 
-    @Deprecated
-    public Object setString(AMQShortString string, String value)
+    FieldTable(QpidByteBuffer input, int len)
     {
-        return setString(AMQShortString.toString(string), value);
+        _strictAMQP = STRICT_AMQP;
+        _encodedForm = input.view(0,len);
+        input.position(input.position()+len);
+        _encodedSize = len;
+        _properties = new LinkedHashMap<>();
     }
 
-    public Object setString(String string, String value)
+    FieldTable(QpidByteBuffer buffer)
     {
-        if (value == null)
-        {
-            return setProperty(string, AMQType.VOID.asTypedValue(null));
-        }
-        else
-        {
-            return setProperty(string, AMQType.LONG_STRING.asTypedValue(value));
-        }
+        _strictAMQP = STRICT_AMQP;
+        _encodedForm = buffer.duplicate();
+        _encodedSize = buffer.remaining();
+        _properties = new LinkedHashMap<>();
     }
 
-    @Deprecated
-    public Object setAsciiString(AMQShortString string, String value)
+    FieldTable(Map<String, Object> properties)
     {
-        return setAsciiString(AMQShortString.toString(string), value);
+        this(properties, STRICT_AMQP);
     }
 
-    public Object setAsciiString(String string, String value)
+    FieldTable(Map<String, Object> properties, boolean strictAMQP)
     {
-        if (value == null)
-        {
-            return setProperty(string, AMQType.VOID.asTypedValue(null));
-        }
-        else
+        _strictAMQP = strictAMQP;
+        long size = 0;
+        Map<String, AMQTypedValue> m = new LinkedHashMap<>();
+        if (properties != null && !properties.isEmpty())
         {
-            return setProperty(string, AMQType.ASCII_STRING.asTypedValue(value));
+            m = new LinkedHashMap<>();
+            for (Map.Entry<String, Object> e : properties.entrySet())
+            {
+                String key = e.getKey();
+                Object val = e.getValue();
+                checkPropertyName(key);
+                AMQTypedValue value = getAMQTypeValue(val);
+                size += EncodingUtils.encodedShortStringLength(e.getKey()) + 1 + value.getEncodingSize();
+                m.put(e.getKey(), value);
+            }
         }
+        _properties = m;
+        _encodedSize = size;
+        _decoded = true;
     }
 
-    @Deprecated
-    public Object setChar(AMQShortString string, char c)
-    {
-        return setChar(AMQShortString.toString(string), c);
-    }
-
-    public Object setChar(String string, char c)
-    {
-        return setProperty(string, AMQType.ASCII_CHARACTER.asTypedValue(c));
-    }
-
-    @Deprecated
-    public Object setFieldArray(AMQShortString string, Collection<?> collection)
-    {
-        return setFieldArray(AMQShortString.toString(string), collection);
-    }
-
-    public Object setFieldArray(String string, Collection<?> collection)
-    {
-        return setProperty(string, AMQType.FIELD_ARRAY.asTypedValue(collection));
-    }
-
-    @Deprecated
-    public Object setBytes(AMQShortString string, byte[] bytes)
-    {
-        return setBytes(AMQShortString.toString(string), bytes);
-    }
-
-    public Object setBytes(String string, byte[] bytes)
+    private synchronized AMQTypedValue getProperty(String key)
     {
-        return setProperty(string, AMQType.BINARY.asTypedValue(bytes));
-    }
-
-    @Deprecated
-    public Object setBytes(AMQShortString string, byte[] bytes, int start, int length)
-    {
-        return setBytes(AMQShortString.toString(string), bytes, start, length);
-    }
-
-    public Object setBytes(String string, byte[] bytes, int start, int length)
-    {
-        byte[] newBytes = new byte[length];
-        System.arraycopy(bytes, start, newBytes, 0, length);
-
-        return setBytes(string, newBytes);
-    }
-
-    @Deprecated
-    public Object setTimestamp(AMQShortString string, long datetime)
-    {
-        return setTimestamp(AMQShortString.toString(string), datetime);
-    }
-
-    public Object setTimestamp(String string, long datetime)
-    {
-        return setProperty(string, AMQType.TIMESTAMP.asTypedValue(datetime));
-    }
-
-    @Deprecated
-    public Object setDecimal(AMQShortString string, BigDecimal decimal)
-    {
-        return setDecimal(AMQShortString.toString(string), decimal);
-    }
-
-    public Object setDecimal(String string, BigDecimal decimal)
-    {
-        if (decimal.longValue() > Integer.MAX_VALUE)
-        {
-            throw new UnsupportedOperationException("AMQP does not support decimals larger than " + Integer.MAX_VALUE);
-        }
-
-        if (decimal.scale() > Byte.MAX_VALUE)
+        AMQTypedValue value = _properties.get(key);
+        if (value == null && !_decoded)
         {
-            throw new UnsupportedOperationException("AMQP does not support decimal scales larger than " + Byte.MAX_VALUE);
+            value = findValueForKey(key);
+            _properties.put(key, value);
         }
-
-        return setProperty(string, AMQType.DECIMAL.asTypedValue(decimal));
-    }
-
-    @Deprecated
-    public Object setVoid(AMQShortString string)
-    {
-        return setVoid(AMQShortString.toString(string));
-    }
-
-    public Object setVoid(String string)
-    {
-        return setProperty(string, AMQType.VOID.asTypedValue(null));
+        return value;
     }
 
-    /**
-     * 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.
-     */
-    @Deprecated
-    public Object setFieldTable(AMQShortString string, FieldTable ftValue)
+    private void decode()
     {
-        return setFieldTable(AMQShortString.toString(string), ftValue);
-    }
+        if (_encodedSize > 0 && _encodedForm != null)
+        {
+            if (!_properties.isEmpty())
+            {
+                _properties.clear();
+            }
+            _encodedForm.mark();
+            try
+            {
+                do
+                {
+                    final String key = AMQShortString.readAMQShortStringAsString(_encodedForm);
 
-    /**
-     * 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 setProperty(string, AMQType.FIELD_TABLE.asTypedValue(ftValue));
+                    checkPropertyName(key);
+                    AMQTypedValue value = AMQTypedValue.readFromBuffer(_encodedForm);
+                    _properties.put(key, value);
+                }
+                while (_encodedForm.hasRemaining());
+            }
+            finally
+            {
+                _encodedForm.reset();
+            }
+        }
     }
 
-    @Deprecated
-    public Object setObject(AMQShortString string, Object object)
+    private void decodeIfNecessary()
     {
-        return setObject(AMQShortString.toString(string), object);
+        if (!_decoded)
+        {
+            decode();
+            _decoded = true;
+        }
     }
 
-    public Object setObject(String string, Object object)
+    private AMQTypedValue getAMQTypeValue(final Object object) throws AMQPInvalidClassException
     {
-        if (object instanceof Boolean)
+        if (object == null)
         {
-            return setBoolean(string, (Boolean) object);
+            return AMQType.VOID.asTypedValue(null);
+        }
+        else if (object instanceof Boolean)
+        {
+            return AMQType.BOOLEAN.asTypedValue(object);
         }
         else if (object instanceof Byte)
         {
-            return setByte(string, (Byte) object);
+            return AMQType.BYTE.asTypedValue(object);
         }
         else if (object instanceof Short)
         {
-            return setShort(string, (Short) object);
+            return AMQType.SHORT.asTypedValue(object);
         }
         else if (object instanceof Integer)
         {
-            return setInteger(string, (Integer) object);
+            return AMQTypedValue.createAMQTypedValue((int) object);
         }
         else if (object instanceof Long)
         {
-            return setLong(string, (Long) object);
+            return AMQTypedValue.createAMQTypedValue((long) object);
         }
         else if (object instanceof Float)
         {
-            return setFloat(string, (Float) object);
+            return AMQType.FLOAT.asTypedValue(object);
         }
         else if (object instanceof Double)
         {
-            return setDouble(string, (Double) object);
+            return AMQType.DOUBLE.asTypedValue(object);
         }
         else if (object instanceof String)
         {
-            return setString(string, (String) object);
+            return AMQType.LONG_STRING.asTypedValue(object);
         }
         else if (object instanceof Character)
         {
-            return setChar(string, (Character) object);
+            return AMQType.ASCII_CHARACTER.asTypedValue(object);
         }
         else if (object instanceof FieldTable)
         {
-            return setFieldTable(string, (FieldTable) object);
+            return AMQType.FIELD_TABLE.asTypedValue(object);
         }
         else if (object instanceof Map)
         {
-            return setFieldTable(string, FieldTable.convertToFieldTable((Map<String,Object>) object));
+            @SuppressWarnings("unchecked")
+            Map<String, Object> map = (Map<String, Object>) object;
+            return AMQType.FIELD_TABLE.asTypedValue(FieldTable.convertToFieldTable(map));
         }
         else if (object instanceof Collection)
         {
-            return setFieldArray(string, (Collection)object);
+            return AMQType.FIELD_ARRAY.asTypedValue(object);
         }
         else if (object instanceof Date)
         {
-            return setTimestamp(string, ((Date) object).getTime());
+            return AMQType.TIMESTAMP.asTypedValue(((Date) object).getTime());
         }
         else if (object instanceof BigDecimal)
         {
-            return setDecimal(string, (BigDecimal) object);
+            final BigDecimal decimal = (BigDecimal) object;
+            if (decimal.longValue() > Integer.MAX_VALUE)
+            {
+                throw new UnsupportedOperationException(String.format("AMQP does not support decimals larger than %d",
+                                                                      Integer.MAX_VALUE));
+            }
+
+            if (decimal.scale() > Byte.MAX_VALUE)
+            {
+                throw new UnsupportedOperationException(String.format(
+                        "AMQP does not support decimal scales larger than %d",
+                        Byte.MAX_VALUE));
+            }
+
+            return AMQType.DECIMAL.asTypedValue(decimal);
         }
         else if (object instanceof byte[])
         {
-            return setBytes(string, (byte[]) object);
+            return AMQType.BINARY.asTypedValue(object);
         }
         else if (object instanceof UUID)
         {
-            return setString(string, object.toString());
+            return AMQType.LONG_STRING.asTypedValue(object.toString());
         }
 
-        throw new AMQPInvalidClassException(AMQPInvalidClassException.INVALID_OBJECT_MSG + (object == null ? "null" : object.getClass()));
-    }
-
-    public boolean isNullStringValue(String name)
-    {
-        AMQTypedValue value = getProperty(name);
-
-        return (value != null) && (value.getType() == AMQType.VOID);
+        throw new AMQPInvalidClassException(AMQPInvalidClassException.INVALID_OBJECT_MSG + object.getClass());
     }
 
     // ***** Methods
 
-    private Enumeration getPropertyNames()
-    {
-        return Collections.enumeration(keys());
-    }
-
-    @Deprecated
-    public boolean propertyExists(AMQShortString propertyName)
-    {
-        return itemExists(AMQShortString.toString(propertyName));
-    }
-
-    public boolean propertyExists(String propertyName)
-    {
-        return itemExists(propertyName);
-    }
-
-    @Deprecated
-    public boolean itemExists(AMQShortString propertyName)
-    {
-        return itemExists(AMQShortString.toString(propertyName));
-    }
-
-    private boolean itemExists(String propertyName)
-    {
-        checkPropertyName(propertyName);
-        initMapIfNecessary();
-
-        return _properties.containsKey(propertyName);
-    }
-
     @Override
     public String toString()
     {
-        initMapIfNecessary();
-
-        return _properties.toString();
+        return getProperties().toString();
     }
 
     private void checkPropertyName(String propertyName)
@@ -877,12 +261,6 @@ public class FieldTable
         }
     }
 
-    @Deprecated
-    protected static void checkIdentiferFormat(AMQShortString propertyName)
-    {
-        checkIdentiferFormat(AMQShortString.toString(propertyName));
-    }
-
     private static void checkIdentiferFormat(String propertyName)
     {
         // AMQP Spec: 4.2.5.5 Field Tables
@@ -903,25 +281,24 @@ public class FieldTable
 
         // AMQ start character
         if (!(Character.isLetter(propertyName.charAt(0)) || (propertyName.charAt(0) == '$')
-                    || (propertyName.charAt(0) == '#') || (propertyName.charAt(0) == '_'))) // Not official AMQP added for JMS.
+              || (propertyName.charAt(0) == '#') || (propertyName.charAt(0)
+                                                     == '_'))) // Not official AMQP added for JMS.
         {
             throw new IllegalArgumentException("Identifier '" + propertyName
-                + "' does not start with a valid AMQP start character");
+                                               + "' does not start with a valid AMQP start character");
         }
     }
 
     // *************************  Byte Buffer Processing
 
-    public void writeToBuffer(QpidByteBuffer buffer)
+    public synchronized void writeToBuffer(QpidByteBuffer buffer)
     {
-        final boolean trace = LOGGER.isDebugEnabled();
-
-        if (trace)
+        if (LOGGER.isDebugEnabled())
         {
             LOGGER.debug("FieldTable::writeToBuffer: Writing encoded length of " + getEncodedSize() + "...");
-            if (_properties != null)
+            if (_decoded)
             {
-                LOGGER.debug(_properties.toString());
+                LOGGER.debug(getProperties().toString());
             }
         }
 
@@ -930,10 +307,9 @@ public class FieldTable
         putDataInBuffer(buffer);
     }
 
-
     public synchronized byte[] getDataAsBytes()
     {
-        if(_encodedForm == null)
+        if (_encodedForm == null)
         {
             byte[] data = new byte[(int) getEncodedSize()];
             QpidByteBuffer buf = QpidByteBuffer.wrap(data);
@@ -946,7 +322,6 @@ public class FieldTable
             _encodedForm.copyTo(encodedCopy);
             return encodedCopy;
         }
-
     }
 
     public long getEncodedSize()
@@ -954,151 +329,57 @@ public class FieldTable
         return _encodedSize;
     }
 
-    private void recalculateEncodedSize()
-    {
-
-        int encodedSize = 0;
-        if (_properties != null)
-        {
-            for (Map.Entry<String, AMQTypedValue> e : _properties.entrySet())
-            {
-                encodedSize += EncodingUtils.encodedShortStringLength(e.getKey());
-                encodedSize++; // the byte for the encoding Type
-                encodedSize += e.getValue().getEncodingSize();
-
-            }
-        }
-
-        _encodedSize = encodedSize;
-    }
-
-    public synchronized void addAll(FieldTable fieldTable)
-    {
-        initMapIfNecessary();
-        fieldTable.initMapIfNecessary();
-        if (fieldTable._properties != null)
-        {
-            _encodedForm = null;
-            _properties.putAll(fieldTable._properties);
-            recalculateEncodedSize();
-        }
-    }
-
     public static Map<String, Object> convertToMap(final FieldTable fieldTable)
     {
         final Map<String, Object> map = new HashMap<>();
 
-        if(fieldTable != null)
-        {
-            fieldTable.processOverElements(
-                    new FieldTableElementProcessor()
-                    {
-
-                        @Override
-                        public boolean processElement(String propertyName, AMQTypedValue value)
-                        {
-                            Object val = value.getValue();
-                            if (val instanceof AMQShortString)
-                            {
-                                val = val.toString();
-                            }
-                            else if (val instanceof FieldTable)
-                            {
-                                val = FieldTable.convertToMap((FieldTable) val);
-                            }
-                            map.put(propertyName, val);
-                            return true;
-                        }
-
-                        @Override
-                        public Object getResult()
-                        {
-                            return map;
-                        }
-                    });
-        }
-        return map;
-    }
-
-    public void clearEncodedForm()
-    {
-        synchronized (this)
+        if (fieldTable != null)
         {
-            if (_properties == null)
+            Map<String, AMQTypedValue> properties = fieldTable.getProperties();
+            if (properties != null)
             {
-                if (_encodedForm != null)
+                for (Map.Entry<String, AMQTypedValue> e : properties.entrySet())
                 {
-                    populateFromBuffer();
+                    Object val = e.getValue().getValue();
+                    if (val instanceof AMQShortString)
+                    {
+                        val = val.toString();
+                    }
+                    else if (val instanceof FieldTable)
+                    {
+                        val = FieldTable.convertToMap((FieldTable) val);
+                    }
+                    map.put(e.getKey(), val);
                 }
             }
-
-            if (_encodedForm != null)
-            {
-                _encodedForm.dispose();
-                _encodedForm = null;
-            }
         }
+        return map;
     }
 
-    public void dispose()
+    public synchronized void clearEncodedForm()
     {
-        synchronized (this)
-        {
-            if (_properties == null)
-            {
-                if (_encodedForm != null)
-                {
-                    _properties = Collections.emptyMap();
-                }
-            }
+        decodeIfNecessary();
 
-            if (_encodedForm != null)
-            {
-                _encodedForm.dispose();
-                _encodedForm = null;
-            }
+        if (_encodedForm != null)
+        {
+            _encodedForm.dispose();
+            _encodedForm = null;
         }
     }
 
-    public synchronized void reallocate()
-    {
-        _encodedForm = QpidByteBuffer.reallocateIfNecessary(_encodedForm);
-    }
-
-
-    public static interface FieldTableElementProcessor
-    {
-        public boolean processElement(String propertyName, AMQTypedValue value);
-
-        public Object getResult();
-    }
-
-    @Deprecated // make it private
-    public Object processOverElements(FieldTableElementProcessor processor)
+    public synchronized void dispose()
     {
-        initMapIfNecessary();
-        if (_properties != null)
+        if (_encodedForm != null)
         {
-            for (Map.Entry<String, AMQTypedValue> e : _properties.entrySet())
-            {
-                boolean result = processor.processElement(e.getKey(), e.getValue());
-                if (!result)
-                {
-                    break;
-                }
-            }
+            _encodedForm.dispose();
+            _encodedForm = null;
         }
-
-        return processor.getResult();
-
+        _properties.clear();
     }
 
     public int size()
     {
-        initMapIfNecessary();
-
-        return _properties.size();
-
+        return getProperties().size();
     }
 
     public boolean isEmpty()
@@ -1106,112 +387,31 @@ public class FieldTable
         return size() == 0;
     }
 
-    @Deprecated
-    public boolean containsKey(AMQShortString key)
-    {
-        return containsKey(AMQShortString.toString(key));
-    }
-
     public boolean containsKey(String key)
     {
-        initMapIfNecessary();
-
-        return _properties.containsKey(key);
+        return getProperties().containsKey(key);
     }
 
     public Set<String> keys()
     {
-        initMapIfNecessary();
-        return new LinkedHashSet<>(_properties.keySet());
-    }
-
-    @Deprecated
-    public Iterator<Map.Entry<AMQShortString, AMQTypedValue>> iterator()
-    {
-        initMapIfNecessary();
-        return _properties.entrySet()
-                          .stream()
-                          .collect(Collectors.toMap(e-> AMQShortString.valueOf(e.getKey()), Map.Entry::getValue))
-                          .entrySet()
-                          .iterator();
+        return new LinkedHashSet<>(getProperties().keySet());
     }
 
     public Object get(String key)
     {
-        return getObject(key);
-    }
-
-    @Deprecated
-    public Object put(AMQShortString key, Object value)
-    {
-        return setObject(AMQShortString.toString(key), value);
-    }
-
-    public Object remove(String key)
-    {
-        AMQTypedValue val = removeKey(key);
-
-        return (val == null) ? null : val.getValue();
-
-    }
-
-    @Deprecated
-    public Object remove(AMQShortString key)
-    {
-        return remove(AMQShortString.toString(key));
-    }
-
-    @Deprecated
-    public AMQTypedValue removeKey(AMQShortString key)
-    {
-        return removeKey(AMQShortString.toString(key));
-    }
-
-    private AMQTypedValue removeKey(String key)
-    {
-        synchronized (this)
-        {
-            initMapIfNecessary();
-            _encodedForm = null;
-        }
-        AMQTypedValue value = _properties.remove(key);
-        if (value == null)
+        checkPropertyName(key);
+        AMQTypedValue value = getProperty(key);
+        if (value != null && value != NOT_PRESENT)
         {
-            return null;
+            return value.getValue();
         }
         else
         {
-            _encodedSize -= EncodingUtils.encodedShortStringLength(key);
-            _encodedSize--;
-            _encodedSize -= value.getEncodingSize();
-
-            return value;
-        }
-
-    }
-
-    public synchronized void clear()
-    {
-        initMapIfNecessary();
-        if (_encodedForm != null)
-        {
-            _encodedForm.dispose();
-            _encodedForm = null;
+            return null;
         }
-        _properties.clear();
-        _encodedSize = 0;
-    }
-
-
-    @Deprecated
-    public Set<AMQShortString> keySet()
-    {
-        initMapIfNecessary();
-
-        return _properties.keySet().stream().map(k->AMQShortString.valueOf(k)).collect(Collectors.toSet());
     }
 
-    private synchronized void putDataInBuffer(QpidByteBuffer buffer)
+    private void putDataInBuffer(QpidByteBuffer buffer)
     {
         if (_encodedForm != null)
         {
@@ -1220,26 +420,12 @@ public class FieldTable
 
             buffer.put(encodedCopy);
         }
-        else if (_properties != null)
+        else if (!_properties.isEmpty())
         {
-            final Iterator<Map.Entry<String, AMQTypedValue>> 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())
+            for (final Map.Entry<String, AMQTypedValue> me : _properties.entrySet())
             {
-                final Map.Entry<String, AMQTypedValue> me = it.next();
-                try
-                {
-                    // Write the actual parameter name
-                    EncodingUtils.writeShortStringBytes(buffer, me.getKey());
-                    me.getValue().writeToBuffer(buffer);
-                }
-                catch (Exception e)
-                {
-                    throw new RuntimeException(e);
-                }
+                EncodingUtils.writeShortStringBytes(buffer, me.getKey());
+                me.getValue().writeToBuffer(buffer);
             }
         }
     }
@@ -1248,9 +434,7 @@ public class FieldTable
     @Override
     public int hashCode()
     {
-        initMapIfNecessary();
-
-        return _properties.hashCode();
+        return getProperties().hashCode();
     }
 
     @Override
@@ -1266,32 +450,52 @@ public class FieldTable
             return false;
         }
 
-        initMapIfNecessary();
-
         FieldTable f = (FieldTable) o;
-        f.initMapIfNecessary();
-
-        return _properties.equals(f._properties);
+        return getProperties().equals(f.getProperties());
     }
 
+    private synchronized Map<String, AMQTypedValue> getProperties()
+    {
+        decodeIfNecessary();
+        return _properties;
+    }
 
-    public static FieldTable convertToFieldTable(Map<String, Object> map)
+    private AMQTypedValue findValueForKey(String key)
     {
-        if (map != null)
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        _encodedForm.mark();
+        try
         {
-            FieldTable table = new FieldTable();
-            for(Map.Entry<String,Object> entry : map.entrySet())
+            while (_encodedForm.hasRemaining())
             {
-                table.setObject(entry.getKey(), entry.getValue());
+                final byte[] bytes = AMQShortString.readAMQShortStringAsBytes(_encodedForm);
+                if (Arrays.equals(keyBytes, bytes))
+                {
+                    return AMQTypedValue.readFromBuffer(_encodedForm);
+                }
+                else
+                {
+                    AMQType type = AMQTypeMap.getType(_encodedForm.get());
+                    type.skip(_encodedForm);
+                }
             }
+        }
+        finally
+        {
+            _encodedForm.reset();
+        }
+        return NOT_PRESENT;
+    }
 
-            return table;
+    public static FieldTable convertToFieldTable(Map<String, Object> map)
+    {
+        if (map != null)
+        {
+            return new FieldTable(map);
         }
         else
         {
             return null;
         }
     }
-
-
 }

http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/ae14be5d/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTableFactory.java
----------------------------------------------------------------------
diff --git a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTableFactory.java b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTableFactory.java
index fc5f97c..bc2ab8b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTableFactory.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/protocol/v0_8/FieldTableFactory.java
@@ -20,16 +20,28 @@
  */
 package org.apache.qpid.server.protocol.v0_8;
 
+import java.util.Map;
+
+import org.apache.qpid.server.bytebuffer.QpidByteBuffer;
+
 public class FieldTableFactory
 {
     private FieldTableFactory()
     {
     }
 
-    public static FieldTable newFieldTable()
+    public static FieldTable createFieldTable(QpidByteBuffer fieldTableBuffer)
     {
-        return new FieldTable();
+        return new FieldTable(fieldTableBuffer);
     }
 
+    public static FieldTable createFieldTable(QpidByteBuffer qpidByteBuffer, int length)
+    {
+        return new FieldTable(qpidByteBuffer, length);
+    }
 
+    public static FieldTable createFieldTable(final Map<String, Object> map)
+    {
+        return new FieldTable(map);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org