NO-JIRA: [AMQP 1-0 Sandbox] merging from trunk

git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/rg-amqp-1-0-sandbox@1295627 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/qpid/java/bdbstore/build.xml b/qpid/java/bdbstore/build.xml
index 9513e7c..af7c108 100644
--- a/qpid/java/bdbstore/build.xml
+++ b/qpid/java/bdbstore/build.xml
@@ -24,7 +24,7 @@
     <import file="../module.xml" />
 
     <property name="bdb.lib.dir" value="${project.root}/lib/bdbstore" />
-    <property name="bdb.version" value="4.0.117" />
+    <property name="bdb.version" value="5.0.34" />
     <property name="bdb.download.url" value="http://download.oracle.com/maven/com/sleepycat/je/${bdb.version}/je-${bdb.version}.jar" />
     <property name="bdb.jar.file" value="${bdb.lib.dir}/je-${bdb.version}.jar" />
 
diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java
index f900159..2e2d2f0 100644
--- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java
+++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStore.java
@@ -22,27 +22,37 @@
 
 import java.io.File;
 import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Queue;
+import java.util.UUID;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
+import com.sleepycat.bind.tuple.LongBinding;
+import com.sleepycat.bind.tuple.StringBinding;
+import com.sleepycat.je.*;
 import org.apache.commons.configuration.Configuration;
 import org.apache.log4j.Logger;
 import org.apache.qpid.AMQStoreException;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.federation.Bridge;
+import org.apache.qpid.server.federation.BrokerLink;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.actors.CurrentActor;
 import org.apache.qpid.server.logging.messages.ConfigStoreMessages;
 import org.apache.qpid.server.logging.messages.MessageStoreMessages;
 import org.apache.qpid.server.logging.messages.TransactionLogMessages;
+import org.apache.qpid.server.message.EnqueableMessage;
 import org.apache.qpid.server.queue.AMQQueue;
 import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
 import org.apache.qpid.server.store.DurableConfigurationStore;
@@ -70,17 +80,6 @@
 import com.sleepycat.bind.EntryBinding;
 import com.sleepycat.bind.tuple.ByteBinding;
 import com.sleepycat.bind.tuple.TupleBinding;
-import com.sleepycat.je.CheckpointConfig;
-import com.sleepycat.je.Cursor;
-import com.sleepycat.je.Database;
-import com.sleepycat.je.DatabaseConfig;
-import com.sleepycat.je.DatabaseEntry;
-import com.sleepycat.je.DatabaseException;
-import com.sleepycat.je.Environment;
-import com.sleepycat.je.EnvironmentConfig;
-import com.sleepycat.je.LockMode;
-import com.sleepycat.je.OperationStatus;
-import com.sleepycat.je.TransactionConfig;
 
 /**
  * BDBMessageStore implements a persistent {@link MessageStore} using the BDB high performance log.
@@ -91,7 +90,7 @@
  * dequeue messages to queues. <tr><td> Generate message identifiers. </table>
  */
 @SuppressWarnings({"unchecked"})
-public class BDBMessageStore implements MessageStore
+public class BDBMessageStore implements MessageStore, DurableConfigurationStore
 {
     private static final Logger _log = Logger.getLogger(BDBMessageStore.class);
 
@@ -107,19 +106,24 @@
     private String DELIVERYDB_NAME = "deliveryDb";
     private String EXCHANGEDB_NAME = "exchangeDb";
     private String QUEUEDB_NAME = "queueDb";
+    private String BRIDGEDB_NAME = "bridges";
+    private String LINKDB_NAME = "links";
+
     private Database _messageMetaDataDb;
     private Database _messageContentDb;
     private Database _queueBindingsDb;
     private Database _deliveryDb;
     private Database _exchangeDb;
     private Database _queueDb;
+    private Database _bridgeDb;
+    private Database _linkDb;
 
     /* =======
      * Schema:
      * =======
-     * 
+     *
      * Queue:
-     * name(AMQShortString) - name(AMQShortString), owner(AMQShortString), 
+     * name(AMQShortString) - name(AMQShortString), owner(AMQShortString),
      *                        arguments(FieldTable encoded as binary), exclusive (boolean)
      *
      * Exchange:
@@ -171,7 +175,7 @@
 
     private boolean _configured;
 
-    
+
     public BDBMessageStore()
     {
         this(DATABASE_FORMAT_VERSION);
@@ -197,27 +201,28 @@
             EXCHANGEDB_NAME += "_v" + version;
 
             QUEUEBINDINGSDB_NAME += "_v" + version;
+
+            LINKDB_NAME += "_v" + version;
+
+            BRIDGEDB_NAME += "_v" + version;
         }
     }
- 
-    public void configureConfigStore(String name, 
-                                     ConfigurationRecoveryHandler recoveryHandler, 
+
+    public void configureConfigStore(String name,
+                                     ConfigurationRecoveryHandler recoveryHandler,
                                      Configuration storeConfiguration,
                                      LogSubject logSubject) throws Exception
     {
-        _logSubject = logSubject;
-        CurrentActor.get().message(_logSubject, ConfigStoreMessages.CREATED(this.getClass().getName()));
+        CurrentActor.get().message(logSubject, ConfigStoreMessages.CREATED(this.getClass().getName()));
 
-        if(_configured)
+        if(!_configured)
         {
-            throw new Exception("ConfigStore already configured");
+            _logSubject = logSubject;
+            configure(name,storeConfiguration);
+            _configured = true;
+            stateTransition(State.CONFIGURING, State.CONFIGURED);
         }
 
-        configure(name,storeConfiguration);
-        
-        _configured = true;
-        stateTransition(State.CONFIGURING, State.CONFIGURED);
-        
         recover(recoveryHandler);
         stateTransition(State.RECOVERING, State.STARTED);
     }
@@ -227,11 +232,14 @@
                                       Configuration storeConfiguration,
                                       LogSubject logSubject) throws Exception
     {
-        CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName()));
+        CurrentActor.get().message(logSubject, MessageStoreMessages.CREATED(this.getClass().getName()));
 
         if(!_configured)
         {
-            throw new Exception("ConfigStore not configured");
+            _logSubject = logSubject;
+            configure(name,storeConfiguration);
+            _configured = true;
+            stateTransition(State.CONFIGURING, State.CONFIGURED);
         }
 
         recoverMessages(recoveryHandler);
@@ -240,24 +248,28 @@
     public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler,
             Configuration storeConfiguration, LogSubject logSubject) throws Exception
     {
-        CurrentActor.get().message(_logSubject, TransactionLogMessages.CREATED(this.getClass().getName()));
+        CurrentActor.get().message(logSubject, TransactionLogMessages.CREATED(this.getClass().getName()));
+
 
         if(!_configured)
         {
-            throw new Exception("ConfigStore not configured");
+            _logSubject = logSubject;
+            configure(name,storeConfiguration);
+            _configured = true;
+            stateTransition(State.CONFIGURING, State.CONFIGURED);
         }
 
         recoverQueueEntries(recoveryHandler);
 
-        
+
     }
 
-    public org.apache.qpid.server.store.TransactionLog.Transaction newTransaction()
+    public org.apache.qpid.server.store.MessageStore.Transaction newTransaction()
     {
         return new BDBTransaction();
     }
 
-    
+
     /**
      * Called after instantiation in order to configure the message store.
      *
@@ -268,8 +280,8 @@
      */
     public boolean configure(String name, Configuration storeConfig) throws Exception
     {
-        File environmentPath = new File(storeConfig.getString(ENVIRONMENT_PATH_PROPERTY, 
-                                System.getProperty("QPID_WORK") + "/bdbstore/" + name));        
+        File environmentPath = new File(storeConfig.getString(ENVIRONMENT_PATH_PROPERTY,
+                                System.getProperty("QPID_WORK") + "/bdbstore/" + name));
         if (!environmentPath.exists())
         {
             if (!environmentPath.mkdirs())
@@ -288,7 +300,7 @@
 
     /**
      * @param environmentPath location for the store to be created in/recovered from
-     * @param readonly if true then don't allow modifications to an existing store, and don't create a new store if none exists 
+     * @param readonly if true then don't allow modifications to an existing store, and don't create a new store if none exists
      * @return whether or not a new store environment was created
      * @throws AMQStoreException
      * @throws DatabaseException
@@ -301,12 +313,12 @@
         _log.info("Configuring BDB message store");
 
         createTupleBindingFactories(_version);
-        
+
         setDatabaseNames(_version);
 
         return setupStore(environmentPath, readonly);
     }
-    
+
     private void createTupleBindingFactories(int version)
     {
             _bindingTupleBindingFactory = new BindingTupleBindingFactory(version);
@@ -406,7 +418,7 @@
         envConfig.setTransactional(true);
         envConfig.setConfigParam("je.lock.nLockTables", "7");
 
-        // Restore 500,000 default timeout.	
+        // Restore 500,000 default timeout.
         //envConfig.setLockTimeout(15000);
 
         // Added to help diagnosis of Deadlock issue
@@ -416,10 +428,10 @@
             envConfig.setConfigParam("je.txn.deadlockStackTrace", "true");
             envConfig.setConfigParam("je.txn.dumpLocks", "true");
         }
-        
+
         // Set transaction mode
         _transactionConfig.setReadCommitted(true);
-        
+
         //This prevents background threads running which will potentially update the store.
         envConfig.setReadOnly(readonly);
         try
@@ -458,13 +470,24 @@
         //This is required if we are wanting read only access.
         dbConfig.setReadOnly(readonly);
 
-        _messageMetaDataDb = _environment.openDatabase(null, MESSAGEMETADATADB_NAME, dbConfig);
-        _queueDb = _environment.openDatabase(null, QUEUEDB_NAME, dbConfig);
-        _exchangeDb = _environment.openDatabase(null, EXCHANGEDB_NAME, dbConfig);
-        _queueBindingsDb = _environment.openDatabase(null, QUEUEBINDINGSDB_NAME, dbConfig);
-        _messageContentDb = _environment.openDatabase(null, MESSAGECONTENTDB_NAME, dbConfig);
-        _deliveryDb = _environment.openDatabase(null, DELIVERYDB_NAME, dbConfig);
+        _messageMetaDataDb = openDatabase(MESSAGEMETADATADB_NAME, dbConfig);
+        _queueDb = openDatabase(QUEUEDB_NAME, dbConfig);
+        _exchangeDb = openDatabase(EXCHANGEDB_NAME, dbConfig);
+        _queueBindingsDb = openDatabase(QUEUEBINDINGSDB_NAME, dbConfig);
+        _messageContentDb = openDatabase(MESSAGECONTENTDB_NAME, dbConfig);
+        _deliveryDb = openDatabase(DELIVERYDB_NAME, dbConfig);
+        _linkDb = openDatabase(LINKDB_NAME, dbConfig);
+        _bridgeDb = openDatabase(BRIDGEDB_NAME, dbConfig);
 
+
+    }
+
+    private Database openDatabase(final String dbName, final DatabaseConfig dbConfig)
+    {
+        // if opening read-only and the database doesn't exist, then you can't create it
+        return dbConfig.getReadOnly() && !_environment.getDatabaseNames().contains(dbName)
+               ? null
+               : _environment.openDatabase(null, dbName, dbConfig);
     }
 
     /**
@@ -520,10 +543,22 @@
             _deliveryDb.close();
         }
 
+        if (_bridgeDb != null)
+        {
+            _log.info("Close bridge database");
+            _bridgeDb.close();
+        }
+
+        if (_linkDb != null)
+        {
+            _log.info("Close link database");
+            _linkDb.close();
+        }
+
         closeEnvironment();
 
         _state = State.CLOSED;
-        
+
         CurrentActor.get().message(_logSubject,MessageStoreMessages.CLOSED());
     }
 
@@ -542,7 +577,7 @@
         }
     }
 
-    
+
     public void recover(ConfigurationRecoveryHandler recoveryHandler) throws AMQStoreException
     {
         stateTransition(State.CONFIGURED, State.RECOVERING);
@@ -556,11 +591,12 @@
 
             ExchangeRecoveryHandler erh = qrh.completeQueueRecovery();
             loadExchanges(erh);
-            
+
             BindingRecoveryHandler brh = erh.completeExchangeRecovery();
             recoverBindings(brh);
-            
-            brh.completeBindingRecovery();
+
+            ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh = brh.completeBindingRecovery();
+            recoverBrokerLinks(lrh);
         }
         catch (DatabaseException e)
         {
@@ -582,13 +618,13 @@
             while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS)
             {
                 QueueRecord queueRecord = (QueueRecord) binding.entryToObject(value);
-                
-                String queueName = queueRecord.getNameShortString() == null ? null : 
+
+                String queueName = queueRecord.getNameShortString() == null ? null :
                                         queueRecord.getNameShortString().asString();
-                String owner = queueRecord.getOwner() == null ? null : 
+                String owner = queueRecord.getOwner() == null ? null :
                                         queueRecord.getOwner().asString();
                 boolean exclusive = queueRecord.isExclusive();
-                
+
                 FieldTable arguments = queueRecord.getArguments();
 
                 qrh.queue(queueName, owner, exclusive, arguments);
@@ -603,8 +639,8 @@
             }
         }
     }
-    
-    
+
+
     private void loadExchanges(ExchangeRecoveryHandler erh) throws DatabaseException
     {
         Cursor cursor = null;
@@ -615,17 +651,17 @@
             DatabaseEntry key = new DatabaseEntry();
             DatabaseEntry value = new DatabaseEntry();
             TupleBinding binding = new ExchangeTB();
-            
+
             while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS)
             {
                 ExchangeRecord exchangeRec = (ExchangeRecord) binding.entryToObject(value);
 
-                String exchangeName = exchangeRec.getNameShortString() == null ? null : 
+                String exchangeName = exchangeRec.getNameShortString() == null ? null :
                                       exchangeRec.getNameShortString().asString();
-                String type = exchangeRec.getType() == null ? null : 
+                String type = exchangeRec.getType() == null ? null :
                               exchangeRec.getType().asString();
                 boolean autoDelete = exchangeRec.isAutoDelete();
-                
+
                 erh.exchange(exchangeName, type, autoDelete);
             }
         }
@@ -638,7 +674,7 @@
         }
 
     }
-    
+
     private void recoverBindings(BindingRecoveryHandler brh) throws DatabaseException
     {
         Cursor cursor = null;
@@ -648,22 +684,22 @@
             DatabaseEntry key = new DatabaseEntry();
             DatabaseEntry value = new DatabaseEntry();
             TupleBinding binding = _bindingTupleBindingFactory.getInstance();
-            
+
             while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS)
             {
                 //yes, this is retrieving all the useful information from the key only.
                 //For table compatibility it shall currently be left as is
                 BindingKey bindingRecord = (BindingKey) binding.entryToObject(key);
-                
+
                 String exchangeName = bindingRecord.getExchangeName() == null ? null :
                                       bindingRecord.getExchangeName().asString();
                 String queueName = bindingRecord.getQueueName() == null ? null :
                                    bindingRecord.getQueueName().asString();
                 String routingKey = bindingRecord.getRoutingKey() == null ? null :
                                     bindingRecord.getRoutingKey().asString();
-                ByteBuffer argumentsBB = (bindingRecord.getArguments() == null ? null : 
+                ByteBuffer argumentsBB = (bindingRecord.getArguments() == null ? null :
                     java.nio.ByteBuffer.wrap(bindingRecord.getArguments().getDataAsBytes()));
-                
+
                 brh.binding(exchangeName, queueName, routingKey, argumentsBB);
             }
         }
@@ -677,6 +713,74 @@
 
     }
 
+
+    private void recoverBrokerLinks(final ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh)
+    {
+        Cursor cursor = null;
+
+        try
+        {
+            cursor = _linkDb.openCursor(null, null);
+            DatabaseEntry key = new DatabaseEntry();
+            DatabaseEntry value = new DatabaseEntry();
+
+            while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS)
+            {
+                UUID id = UUIDTupleBinding.getInstance().entryToObject(key);
+                long createTime = LongBinding.entryToLong(value);
+                Map<String,String> arguments = StringMapBinding.getInstance().entryToObject(value);
+
+                ConfigurationRecoveryHandler.BridgeRecoveryHandler brh = lrh.brokerLink(id, createTime, arguments);
+
+                recoverBridges(brh, id);
+            }
+        }
+        finally
+        {
+            if (cursor != null)
+            {
+                cursor.close();
+            }
+        }
+
+    }
+
+    private void recoverBridges(final ConfigurationRecoveryHandler.BridgeRecoveryHandler brh, final UUID linkId)
+    {
+        Cursor cursor = null;
+
+        try
+        {
+            cursor = _bridgeDb.openCursor(null, null);
+            DatabaseEntry key = new DatabaseEntry();
+            DatabaseEntry value = new DatabaseEntry();
+
+            while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS)
+            {
+                UUID id = UUIDTupleBinding.getInstance().entryToObject(key);
+
+                UUID parentId = UUIDTupleBinding.getInstance().entryToObject(value);
+                if(parentId.equals(linkId))
+                {
+
+                    long createTime = LongBinding.entryToLong(value);
+                    Map<String,String> arguments = StringMapBinding.getInstance().entryToObject(value);
+                    brh.bridge(id,createTime,arguments);
+                }
+            }
+            brh.completeBridgeRecoveryForLink();
+        }
+        finally
+        {
+            if (cursor != null)
+            {
+                cursor.close();
+            }
+        }
+
+    }
+
+
     private void recoverMessages(MessageStoreRecoveryHandler msrh) throws DatabaseException
     {
         StoredMessageRecoveryHandler mrh = msrh.begin();
@@ -686,8 +790,6 @@
         {
             cursor = _messageMetaDataDb.openCursor(null, null);
             DatabaseEntry key = new DatabaseEntry();
-            EntryBinding keyBinding = TupleBinding.getPrimitiveBinding(Long.class);;
-
             DatabaseEntry value = new DatabaseEntry();
             EntryBinding valueBinding = _metaDataTupleBindingFactory.getInstance();
 
@@ -695,12 +797,12 @@
 
             while (cursor.getNext(key, value, LockMode.RMW) == OperationStatus.SUCCESS)
             {
-                long messageId = (Long) keyBinding.entryToObject(key);
+                long messageId = LongBinding.entryToLong(key);
                 StorableMessageMetaData metaData = (StorableMessageMetaData) valueBinding.entryToObject(value);
 
                 StoredBDBMessage message = new StoredBDBMessage(messageId, metaData, false);
                 mrh.message(message);
-                
+
                 maxId = Math.max(maxId, messageId);
             }
 
@@ -719,14 +821,14 @@
             }
         }
     }
-    
-    private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler) 
+
+    private void recoverQueueEntries(TransactionLogRecoveryHandler recoveryHandler)
     throws DatabaseException
     {
         QueueEntryRecoveryHandler qerh = recoveryHandler.begin(this);
 
         ArrayList<QueueEntryKey> entries = new ArrayList<QueueEntryKey>();
-        
+
         Cursor cursor = null;
         try
         {
@@ -751,12 +853,12 @@
             {
                 cursor = null;
             }
-            
+
             for(QueueEntryKey entry : entries)
             {
                 AMQShortString queueName = entry.getQueueName();
                 long messageId = entry.getMessageId();
-                
+
                 qerh.queueEntry(queueName.asString(),messageId);
             }
         }
@@ -781,36 +883,39 @@
      *
      * @param messageId Identifies the message to remove.
      *
-     * @throws AMQInternalException If the operation fails for any reason.
+     * @throws AMQStoreException If the operation fails for any reason.
      */
-    public void removeMessage(Long messageId) throws AMQStoreException
+    public void removeMessage(long messageId) throws AMQStoreException
     {
+        removeMessage(messageId, true);
+    }
+    public void removeMessage(long messageId, boolean sync) throws AMQStoreException
+    {
+
         // _log.debug("public void removeMessage(Long messageId = " + messageId): called");
 
         com.sleepycat.je.Transaction tx = null;
-        
+
         Cursor cursor = null;
         try
         {
             tx = _environment.beginTransaction(null, null);
-            
+
             //remove the message meta data from the store
             DatabaseEntry key = new DatabaseEntry();
-            EntryBinding metaKeyBindingTuple = TupleBinding.getPrimitiveBinding(Long.class);
-            metaKeyBindingTuple.objectToEntry(messageId, key);
+            LongBinding.longToEntry(messageId, key);
 
             if (_log.isDebugEnabled())
             {
                 _log.debug("Removing message id " + messageId);
             }
 
-            
+
             OperationStatus status = _messageMetaDataDb.delete(tx, key);
             if (status == OperationStatus.NOTFOUND)
             {
-                tx.abort();
-
-                throw new AMQStoreException("Message metadata not found for message id " + messageId);
+                _log.info("Message not found (attempt to remove failed - probably application initiated rollback) " +
+                messageId);
             }
 
             if (_log.isDebugEnabled())
@@ -826,7 +931,7 @@
             TupleBinding<MessageContentKey> contentKeyTupleBinding = new MessageContentKeyTB_5();
             contentKeyTupleBinding.objectToEntry(mck, contentKeyEntry);
 
-            //Use a partial record for the value to prevent retrieving the 
+            //Use a partial record for the value to prevent retrieving the
             //data itself as we only need the key to identify what to remove.
             DatabaseEntry value = new DatabaseEntry();
             value.setPartial(0, 0, true);
@@ -837,7 +942,7 @@
             while (status == OperationStatus.SUCCESS)
             {
                 mck = (MessageContentKey_5) contentKeyTupleBinding.entryToObject(contentKeyEntry);
-                
+
                 if(mck.getMessageId() != messageId)
                 {
                     //we have exhausted all chunks for this message id, break
@@ -846,34 +951,34 @@
                 else
                 {
                     status = cursor.delete();
-                    
+
                     if(status == OperationStatus.NOTFOUND)
                     {
                         cursor.close();
                         cursor = null;
-                        
+
                         tx.abort();
                         throw new AMQStoreException("Content chunk offset" + mck.getOffset() + " not found for message " + messageId);
                     }
-                    
+
                     if (_log.isDebugEnabled())
                     {
                         _log.debug("Deleted content chunk offset " + mck.getOffset() + " for message " + messageId);
                     }
                 }
-                
+
                 status = cursor.getNext(contentKeyEntry, value, LockMode.RMW);
             }
 
             cursor.close();
             cursor = null;
-            
-            commit(tx, true);
+
+            commit(tx, sync);
         }
         catch (DatabaseException e)
         {
             e.printStackTrace();
-            
+
             if (tx != null)
             {
                 try
@@ -883,7 +988,7 @@
                         cursor.close();
                         cursor = null;
                     }
-                    
+
                     tx.abort();
                 }
                 catch (DatabaseException e1)
@@ -917,7 +1022,7 @@
     {
         if (_state != State.RECOVERING)
         {
-            ExchangeRecord exchangeRec = new ExchangeRecord(exchange.getNameShortString(), 
+            ExchangeRecord exchangeRec = new ExchangeRecord(exchange.getNameShortString(),
                                              exchange.getTypeShortString(), exchange.isAutoDelete());
 
             DatabaseEntry key = new DatabaseEntry();
@@ -974,20 +1079,20 @@
 
         if (_state != State.RECOVERING)
         {
-            BindingKey bindingRecord = new BindingKey(exchange.getNameShortString(), 
+            BindingKey bindingRecord = new BindingKey(exchange.getNameShortString(),
                                                 queue.getNameShortString(), routingKey, args);
 
             DatabaseEntry key = new DatabaseEntry();
             EntryBinding keyBinding = _bindingTupleBindingFactory.getInstance();
-            
+
             keyBinding.objectToEntry(bindingRecord, key);
 
-            //yes, this is writing out 0 as a value and putting all the 
+            //yes, this is writing out 0 as a value and putting all the
             //useful info into the key, don't ask me why. For table
             //compatibility it shall currently be left as is
             DatabaseEntry value = new DatabaseEntry();
             ByteBinding.byteToEntry((byte) 0, value);
-            
+
             try
             {
                 _queueBindingsDb.put(null, key, value);
@@ -1043,16 +1148,16 @@
         {
             _log.debug("public void createQueue(AMQQueue queue(" + queue.getName() + ") = " + queue + "): called");
         }
-        
-        QueueRecord queueRecord= new QueueRecord(queue.getNameShortString(), 
+
+        QueueRecord queueRecord= new QueueRecord(queue.getNameShortString(),
                                                 queue.getOwner(), queue.isExclusive(), arguments);
-        
+
         createQueue(queueRecord);
     }
 
     /**
-     * Makes the specified queue persistent. 
-     * 
+     * Makes the specified queue persistent.
+     *
      * Only intended for direct use during store upgrades.
      *
      * @param queueRecord     Details of the queue to store.
@@ -1086,7 +1191,7 @@
     /**
      * Updates the specified queue in the persistent store, IF it is already present. If the queue
      * is not present in the store, it will not be added.
-     * 
+     *
      * NOTE: Currently only updates the exclusivity.
      *
      * @param queue The queue to update the entry for.
@@ -1112,13 +1217,13 @@
             OperationStatus status = _queueDb.get(null, key, value, LockMode.DEFAULT);
             if(status == OperationStatus.SUCCESS)
             {
-                //read the existing record and apply the new exclusivity setting 
+                //read the existing record and apply the new exclusivity setting
                 QueueRecord queueRecord = (QueueRecord) queueBinding.entryToObject(value);
                 queueRecord.setExclusive(queue.isExclusive());
-                
+
                 //write the updated entry to the store
                 queueBinding.objectToEntry(queueRecord, newValue);
-                
+
                 _queueDb.put(null, key, newValue);
             }
             else if(status != OperationStatus.NOTFOUND)
@@ -1147,7 +1252,7 @@
         {
             _log.debug("public void removeQueue(AMQShortString name = " + name + "): called");
         }
-            
+
         DatabaseEntry key = new DatabaseEntry();
         EntryBinding keyBinding = new AMQShortStringTB();
         keyBinding.objectToEntry(name, key);
@@ -1165,6 +1270,90 @@
         }
     }
 
+    public void createBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+        if (_state != State.RECOVERING)
+        {
+            DatabaseEntry key = new DatabaseEntry();
+            UUIDTupleBinding.getInstance().objectToEntry(link.getId(), key);
+
+            DatabaseEntry value = new DatabaseEntry();
+            LongBinding.longToEntry(link.getCreateTime(),value);
+            StringMapBinding.getInstance().objectToEntry(link.getArguments(), value);
+
+            try
+            {
+                _linkDb.put(null, key, value);
+            }
+            catch (DatabaseException e)
+            {
+                throw new AMQStoreException("Error writing Link  " + link
+                                            + " to database: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+        DatabaseEntry key = new DatabaseEntry();
+        UUIDTupleBinding.getInstance().objectToEntry(link.getId(), key);
+        try
+        {
+            OperationStatus status = _linkDb.delete(null, key);
+            if (status == OperationStatus.NOTFOUND)
+            {
+                throw new AMQStoreException("Link " + link + " not found");
+            }
+        }
+        catch (DatabaseException e)
+        {
+            throw new AMQStoreException("Error deleting the Link " + link + " from database: " + e.getMessage(), e);
+        }
+    }
+
+    public void createBridge(final Bridge bridge) throws AMQStoreException
+    {
+        if (_state != State.RECOVERING)
+        {
+            DatabaseEntry key = new DatabaseEntry();
+            UUIDTupleBinding.getInstance().objectToEntry(bridge.getId(), key);
+
+            DatabaseEntry value = new DatabaseEntry();
+            UUIDTupleBinding.getInstance().objectToEntry(bridge.getLink().getId(),value);
+            LongBinding.longToEntry(bridge.getCreateTime(),value);
+            StringMapBinding.getInstance().objectToEntry(bridge.getArguments(), value);
+
+            try
+            {
+                _bridgeDb.put(null, key, value);
+            }
+            catch (DatabaseException e)
+            {
+                throw new AMQStoreException("Error writing Bridge  " + bridge
+                                            + " to database: " + e.getMessage(), e);
+            }
+
+        }
+    }
+
+    public void deleteBridge(final Bridge bridge) throws AMQStoreException
+    {
+        DatabaseEntry key = new DatabaseEntry();
+        UUIDTupleBinding.getInstance().objectToEntry(bridge.getId(), key);
+        try
+        {
+            OperationStatus status = _bridgeDb.delete(null, key);
+            if (status == OperationStatus.NOTFOUND)
+            {
+                throw new AMQStoreException("Bridge " + bridge + " not found");
+            }
+        }
+        catch (DatabaseException e)
+        {
+            throw new AMQStoreException("Error deleting the Bridge " + bridge + " from database: " + e.getMessage(), e);
+        }
+    }
+
     /**
      * Places a message onto a specified queue, in a given transaction.
      *
@@ -1174,12 +1363,13 @@
      *
      * @throws AMQStoreException If the operation fails for any reason.
      */
-    public void enqueueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue, Long messageId) throws AMQStoreException
+    public void enqueueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue,
+                               long messageId) throws AMQStoreException
     {
         // _log.debug("public void enqueueMessage(Transaction tx = " + tx + ", AMQShortString name = " + name + ", Long messageId): called");
 
-        AMQShortString name = new AMQShortString(queue.getResourceName());
-        
+        AMQShortString name = AMQShortString.valueOf(queue.getResourceName());
+
         DatabaseEntry key = new DatabaseEntry();
         EntryBinding keyBinding = new QueueEntryTB();
         QueueEntryKey dd = new QueueEntryKey(name, messageId);
@@ -1212,7 +1402,8 @@
      *
      * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
      */
-    public void dequeueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue, Long messageId) throws AMQStoreException
+    public void dequeueMessage(final com.sleepycat.je.Transaction tx, final TransactionLogResource queue,
+                               long messageId) throws AMQStoreException
     {
         AMQShortString name = new AMQShortString(queue.getResourceName());
 
@@ -1226,7 +1417,7 @@
         {
             _log.debug("Dequeue message id " + messageId);
         }
-        
+
         try
         {
 
@@ -1234,7 +1425,7 @@
             if (status == OperationStatus.NOTFOUND)
             {
                 throw new AMQStoreException("Unable to find message with id " + messageId + " on queue " + name);
-            } 
+            }
             else if (status != OperationStatus.SUCCESS)
             {
                 throw new AMQStoreException("Unable to remove message with id " + messageId + " on queue " + name);
@@ -1269,12 +1460,12 @@
         //{
         //    _log.debug("public void commitTranImpl() called with (Transaction=" + tx + ", syncCommit= "+ syncCommit + ")");
         //}
-        
+
         if (tx == null)
         {
             throw new AMQStoreException("Fatal internal error: transactional is null at commitTran");
         }
-        
+
         StoreFuture result;
         try
         {
@@ -1289,7 +1480,7 @@
         {
             throw new AMQStoreException("Error commit tx: " + e.getMessage(), e);
         }
-        
+
         return result;
     }
 
@@ -1383,7 +1574,7 @@
      *
      * @return A fresh message id.
      */
-    public Long getNewMessageId()
+    public long getNewMessageId()
     {
         return _messageId.incrementAndGet();
     }
@@ -1398,7 +1589,7 @@
      *
      * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
      */
-    protected void addContent(final com.sleepycat.je.Transaction tx, Long messageId, int offset, 
+    protected void addContent(final com.sleepycat.je.Transaction tx, long messageId, int offset,
                                       ByteBuffer contentBody) throws AMQStoreException
     {
         DatabaseEntry key = new DatabaseEntry();
@@ -1436,7 +1627,8 @@
      *
      * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
      */
-    private void storeMetaData(final com.sleepycat.je.Transaction tx, Long messageId, StorableMessageMetaData messageMetaData)
+    private void storeMetaData(final com.sleepycat.je.Transaction tx, long messageId,
+                               StorableMessageMetaData messageMetaData)
             throws AMQStoreException
     {
         if (_log.isDebugEnabled())
@@ -1446,10 +1638,9 @@
         }
 
         DatabaseEntry key = new DatabaseEntry();
-        EntryBinding keyBinding = TupleBinding.getPrimitiveBinding(Long.class);
-        keyBinding.objectToEntry(messageId, key);
+        LongBinding.longToEntry(messageId, key);
         DatabaseEntry value = new DatabaseEntry();
-        
+
         TupleBinding messageBinding = _metaDataTupleBindingFactory.getInstance();
         messageBinding.objectToEntry(messageMetaData, value);
         try
@@ -1475,7 +1666,7 @@
      *
      * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
      */
-    public StorableMessageMetaData getMessageMetaData(Long messageId) throws AMQStoreException
+    public StorableMessageMetaData getMessageMetaData(long messageId) throws AMQStoreException
     {
         if (_log.isDebugEnabled())
         {
@@ -1484,8 +1675,7 @@
         }
 
         DatabaseEntry key = new DatabaseEntry();
-        EntryBinding keyBinding = TupleBinding.getPrimitiveBinding(Long.class);
-        keyBinding.objectToEntry(messageId, key);
+        LongBinding.longToEntry(messageId, key);
         DatabaseEntry value = new DatabaseEntry();
         TupleBinding messageBinding = _metaDataTupleBindingFactory.getInstance();
 
@@ -1519,17 +1709,17 @@
      *
      * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
      */
-    public int getContent(Long messageId, int offset, ByteBuffer dst) throws AMQStoreException
-    {    
+    public int getContent(long messageId, int offset, ByteBuffer dst) throws AMQStoreException
+    {
         DatabaseEntry contentKeyEntry = new DatabaseEntry();
-        
-        //Start from 0 offset and search for the starting chunk. 
+
+        //Start from 0 offset and search for the starting chunk.
         MessageContentKey_5 mck = new MessageContentKey_5(messageId, 0);
         TupleBinding<MessageContentKey> contentKeyTupleBinding = new MessageContentKeyTB_5();
         contentKeyTupleBinding.objectToEntry(mck, contentKeyEntry);
         DatabaseEntry value = new DatabaseEntry();
         TupleBinding<ByteBuffer> contentTupleBinding = new ContentTB();
-        
+
         if (_log.isDebugEnabled())
         {
             _log.debug("Message Id: " + messageId + " Getting content body from offset: " + offset);
@@ -1537,32 +1727,32 @@
 
         int written = 0;
         int seenSoFar = 0;
-        
+
         Cursor cursor = null;
         try
         {
             cursor = _messageContentDb.openCursor(null, null);
-            
+
             OperationStatus status = cursor.getSearchKeyRange(contentKeyEntry, value, LockMode.READ_UNCOMMITTED);
 
             while (status == OperationStatus.SUCCESS)
             {
                 mck = (MessageContentKey_5) contentKeyTupleBinding.entryToObject(contentKeyEntry);
                 long id = mck.getMessageId();
-                
+
                 if(id != messageId)
                 {
                     //we have exhausted all chunks for this message id, break
                     break;
                 }
-                
+
                 int offsetInMessage = mck.getOffset();
                 ByteBuffer buf = (ByteBuffer) contentTupleBinding.entryToObject(value);
-                
+
                 final int size = (int) buf.limit();
-                
+
                 seenSoFar += size;
-                
+
                 if(seenSoFar >= offset)
                 {
                     byte[] dataAsBytes = buf.array();
@@ -1581,7 +1771,7 @@
                         break;
                     }
                 }
-                
+
                 status = cursor.getNext(contentKeyEntry, value, LockMode.RMW);
             }
 
@@ -1636,7 +1826,7 @@
     {
         return _bindingTupleBindingFactory;
     }
-    
+
     protected MessageMetaDataTupleBindingFactory getMetaDataTupleBindingFactory()
     {
         return _metaDataTupleBindingFactory;
@@ -1743,7 +1933,7 @@
 
         BDBCommitFuture commitFuture = new BDBCommitFuture(_commitThread, tx, syncCommit);
         commitFuture.commit();
-        
+
         return commitFuture;
     }
 
@@ -1778,7 +1968,6 @@
             {
                 _log.debug("public synchronized void complete(): called (Transaction = " + _tx + ")");
             }
-
             _complete = true;
 
             notifyAll();
@@ -1799,36 +1988,22 @@
         {
             //_log.debug("public void commit(): called");
 
-            _commitThread.addJob(this);
-            
+            _commitThread.addJob(this, _syncCommit);
+
             if(!_syncCommit)
             {
                 _log.debug("CommitAsync was requested, returning immediately.");
                 return;
             }
-            
-            synchronized (BDBCommitFuture.this)
+
+            waitForCompletion();
+            // _log.debug("Commit completed, _databaseException = " + _databaseException);
+
+            if (_databaseException != null)
             {
-                while (!_complete)
-                {
-                    try
-                    {
-                        wait(250);
-                    }
-                    catch (InterruptedException e)
-                    {
-                        // _log.error("Unexpected thread interruption: " + e, e);
-                        throw new RuntimeException(e);
-                    }
-                }
-
-                // _log.debug("Commit completed, _databaseException = " + _databaseException);
-
-                if (_databaseException != null)
-                {
-                    throw _databaseException;
-                }
+                throw _databaseException;
             }
+
         }
 
         public synchronized boolean isComplete()
@@ -1836,10 +2011,11 @@
             return _complete;
         }
 
-        public void waitForCompletion()
+        public synchronized void waitForCompletion()
         {
             while (!isComplete())
             {
+                _commitThread.explicitNotify();
                 try
                 {
                     wait(250);
@@ -1866,7 +2042,7 @@
         // private final Logger _log = Logger.getLogger(CommitThread.class);
 
         private final AtomicBoolean _stopped = new AtomicBoolean(false);
-        private final AtomicReference<Queue<BDBCommitFuture>> _jobQueue = new AtomicReference<Queue<BDBCommitFuture>>(new ConcurrentLinkedQueue<BDBCommitFuture>());
+        private final Queue<BDBCommitFuture> _jobQueue = new ConcurrentLinkedQueue<BDBCommitFuture>();
         private final CheckpointConfig _config = new CheckpointConfig();
         private final Object _lock = new Object();
 
@@ -1877,6 +2053,14 @@
 
         }
 
+        public void explicitNotify()
+        {
+            synchronized (_lock)
+            {
+                _lock.notify();
+            }
+        }
+
         public void run()
         {
             while (!_stopped.get())
@@ -1887,7 +2071,7 @@
                     {
                         try
                         {
-                            // RHM-7 Periodically wake up and check, just in case we 
+                            // RHM-7 Periodically wake up and check, just in case we
                             // missed a notification. Don't want to lock the broker hard.
                             _lock.wait(250);
                         }
@@ -1905,24 +2089,24 @@
         {
             // _log.debug("private void processJobs(): called");
 
-            // we replace the old queue atomically with a new one and this avoids any need to
-            // copy elements out of the queue
-            Queue<BDBCommitFuture> jobs = _jobQueue.getAndSet(new ConcurrentLinkedQueue<BDBCommitFuture>());
+            int size = _jobQueue.size();
 
             try
             {
-                // _environment.checkpoint(_config);
-                _environment.sync();
+                _environment.flushLog(true);
 
-                for (BDBCommitFuture commit : jobs)
+                for(int i = 0; i < size; i++)
                 {
+                    BDBCommitFuture commit = _jobQueue.poll();
                     commit.complete();
                 }
+
             }
             catch (DatabaseException e)
             {
-                for (BDBCommitFuture commit : jobs)
+                for(int i = 0; i < size; i++)
                 {
+                    BDBCommitFuture commit = _jobQueue.poll();
                     commit.abort(e);
                 }
             }
@@ -1931,15 +2115,19 @@
 
         private boolean hasJobs()
         {
-            return !_jobQueue.get().isEmpty();
+            return !_jobQueue.isEmpty();
         }
 
-        public void addJob(BDBCommitFuture commit)
+        public void addJob(BDBCommitFuture commit, final boolean sync)
         {
-            synchronized (_lock)
+
+            _jobQueue.add(commit);
+            if(sync)
             {
-                _jobQueue.get().add(commit);
-                _lock.notifyAll();
+                synchronized (_lock)
+                {
+                    _lock.notifyAll();
+                }
             }
         }
 
@@ -1952,14 +2140,17 @@
             }
         }
     }
-    
-    
+
+
     private class StoredBDBMessage implements StoredMessage
     {
 
         private final long _messageId;
         private volatile SoftReference<StorableMessageMetaData> _metaDataRef;
-        private com.sleepycat.je.Transaction _txn;
+
+        private StorableMessageMetaData _metaData;
+        private volatile SoftReference<byte[]> _dataRef;
+        private byte[] _data;
 
         StoredBDBMessage(long messageId, StorableMessageMetaData metaData)
         {
@@ -1973,22 +2164,15 @@
             try
             {
                 _messageId = messageId;
+                _metaData = metaData;
 
                 _metaDataRef = new SoftReference<StorableMessageMetaData>(metaData);
-                if(persist)
-                {
-                    _txn = _environment.beginTransaction(null, null);
-                    storeMetaData(_txn, messageId, metaData);
-                }
+
             }
             catch (DatabaseException e)
             {
                 throw new RuntimeException(e);
             }
-            catch (AMQStoreException e)
-            {
-                throw new RuntimeException(e);
-            }
 
         }
 
@@ -2018,58 +2202,114 @@
 
         public void addContent(int offsetInMessage, java.nio.ByteBuffer src)
         {
-            try
+            src = src.slice();
+
+            if(_data == null)
             {
-                BDBMessageStore.this.addContent(_txn, _messageId, offsetInMessage, src);
+                _data = new byte[src.remaining()];
+                _dataRef = new SoftReference<byte[]>(_data);
+                src.duplicate().get(_data);
             }
-            catch (AMQStoreException e)
+            else
             {
-                throw new RuntimeException(e);
+                byte[] oldData = _data;
+                _data = new byte[oldData.length + src.remaining()];
+                _dataRef = new SoftReference<byte[]>(_data);
+
+                System.arraycopy(oldData,0,_data,0,oldData.length);
+                src.duplicate().get(_data, oldData.length, src.remaining());
             }
+
         }
 
         public int getContent(int offsetInMessage, java.nio.ByteBuffer dst)
         {
-            try
+            byte[] data = _dataRef == null ? null : _dataRef.get();
+            if(data != null)
             {
-                return BDBMessageStore.this.getContent(_messageId, offsetInMessage, dst);
+                int length = Math.min(dst.remaining(), data.length - offsetInMessage);
+                dst.put(data, offsetInMessage, length);
+                return length;
             }
-            catch (AMQStoreException e)
+            else
             {
-                throw new RuntimeException(e);
+                try
+                {
+                    return BDBMessageStore.this.getContent(_messageId, offsetInMessage, dst);
+                }
+                catch (AMQStoreException e)
+                {
+                    throw new RuntimeException(e);
+                }
             }
         }
 
-        public StoreFuture flushToStore()
+        public ByteBuffer getContent(int offsetInMessage, int size)
         {
-            try
+            byte[] data = _dataRef == null ? null : _dataRef.get();
+            if(data != null)
             {
-                if(_txn != null)
+                return ByteBuffer.wrap(data,offsetInMessage,size);
+            }
+            else
+            {
+                ByteBuffer buf = ByteBuffer.allocate(size);
+                getContent(offsetInMessage, buf);
+                buf.position(0);
+                return  buf;
+            }
+        }
+
+        synchronized void store(com.sleepycat.je.Transaction txn)
+        {
+
+            if(_metaData != null)
+            {
+                try
                 {
-                    //if(_log.isDebugEnabled())
-                    //{
-                    //   _log.debug("Flushing message " + _messageId + " to store");
-                    //}
-                    BDBMessageStore.this.commitTranImpl(_txn, true);
+                    _dataRef = new SoftReference<byte[]>(_data);
+                    BDBMessageStore.this.storeMetaData(txn, _messageId, _metaData);
+                    BDBMessageStore.this.addContent(txn, _messageId, 0,
+                                                    _data == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(_data));
+                }
+                catch(DatabaseException e)
+                {
+                    throw new RuntimeException(e);
+                }
+                catch (AMQStoreException e)
+                {
+                    throw new RuntimeException(e);
+                }
+                catch (RuntimeException e)
+                {
+                    e.printStackTrace();
+                    throw e;
+                }
+                finally
+                {
+                    _metaData = null;
+                    _data = null;
                 }
             }
-            catch (AMQStoreException e)
+        }
+
+        public synchronized StoreFuture flushToStore()
+        {
+            if(_metaData != null)
             {
-                throw new RuntimeException(e);
-            }
-            finally
-            {
-                _txn = null;
+                com.sleepycat.je.Transaction txn = _environment.beginTransaction(null, null);
+                store(txn);
+                BDBMessageStore.this.commit(txn,true);
+
             }
             return IMMEDIATE_FUTURE;
         }
 
         public void remove()
         {
-            flushToStore();
             try
             {
-                BDBMessageStore.this.removeMessage(_messageId);
+                BDBMessageStore.this.removeMessage(_messageId, false);
             }
             catch (AMQStoreException e)
             {
@@ -2094,12 +2334,27 @@
             }
         }
 
-        public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+        public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
+        {
+            if(message.getStoredMessage() instanceof StoredBDBMessage)
+            {
+                ((StoredBDBMessage)message.getStoredMessage()).store(_txn);
+            }
+
+            BDBMessageStore.this.enqueueMessage(_txn, queue, message.getMessageNumber());
+        }
+
+        public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
+        {
+            BDBMessageStore.this.dequeueMessage(_txn, queue, message.getMessageNumber());
+        }
+
+        public void enqueueMessage(TransactionLogResource queue, long messageId) throws AMQStoreException
         {
             BDBMessageStore.this.enqueueMessage(_txn, queue, messageId);
         }
 
-        public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+        public void dequeueMessage(TransactionLogResource queue, long messageId) throws AMQStoreException
         {
             BDBMessageStore.this.dequeueMessage(_txn, queue, messageId);
 
diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/StringMapBinding.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/StringMapBinding.java
new file mode 100644
index 0000000..f8fd39e
--- /dev/null
+++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/StringMapBinding.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store.berkeleydb;
+
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class StringMapBinding extends TupleBinding<Map<String,String>>
+{
+    
+    private static final StringMapBinding INSTANCE = new StringMapBinding();
+    
+    public Map<String, String> entryToObject(final TupleInput tupleInput)
+    {
+        int entries = tupleInput.readInt();
+        Map<String,String> map = new HashMap<String,String>(entries);
+        for(int i = 0; i < entries; i++)
+        {
+            map.put(tupleInput.readString(), tupleInput.readString());
+        }
+        return map;
+    }
+
+    
+    public void objectToEntry(final Map<String, String> stringStringMap, final TupleOutput tupleOutput)
+    {
+        tupleOutput.writeInt(stringStringMap.size());
+        for(Map.Entry<String,String> entry : stringStringMap.entrySet())
+        {
+            tupleOutput.writeString(entry.getKey());
+            tupleOutput.writeString(entry.getValue());
+        }
+    }
+
+    public static StringMapBinding getInstance()
+    {
+        return INSTANCE;
+    }
+}
diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/UUIDTupleBinding.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/UUIDTupleBinding.java
new file mode 100644
index 0000000..c1a5d47
--- /dev/null
+++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/UUIDTupleBinding.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.store.berkeleydb;
+
+import com.sleepycat.bind.tuple.TupleBinding;
+import com.sleepycat.bind.tuple.TupleInput;
+import com.sleepycat.bind.tuple.TupleOutput;
+
+import java.util.UUID;
+
+public class UUIDTupleBinding extends TupleBinding<UUID>
+{
+    private static final UUIDTupleBinding INSTANCE = new UUIDTupleBinding();
+    
+    public UUID entryToObject(final TupleInput tupleInput)
+    {
+        return new UUID(tupleInput.readLong(), tupleInput.readLong());
+    }
+
+    public void objectToEntry(final UUID uuid, final TupleOutput tupleOutput)
+    {
+        tupleOutput.writeLong(uuid.getMostSignificantBits());
+        tupleOutput.writeLong(uuid.getLeastSignificantBits());        
+    }
+
+    public static UUIDTupleBinding getInstance()
+    {
+        return INSTANCE;
+    }
+
+
+}
diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java
index 975e558..68f1e7c 100644
--- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java
+++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/tuples/QueueEntryTB.java
@@ -33,7 +33,7 @@
     public QueueEntryKey entryToObject(TupleInput tupleInput)
     {
         AMQShortString queueName = AMQShortStringEncoding.readShortString(tupleInput);
-        Long messageId = tupleInput.readLong();
+        long messageId = tupleInput.readLong();
 
         return new QueueEntryKey(queueName, messageId);
     }
diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
index ef31b78..6c890da 100644
--- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
+++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBMessageStoreTest.java
@@ -32,13 +32,11 @@
 import org.apache.qpid.framing.MethodRegistry;
 import org.apache.qpid.framing.ProtocolVersion;
 import org.apache.qpid.framing.abstraction.MessagePublishInfo;
-import org.apache.qpid.server.message.MessageMetaData;
-import org.apache.qpid.server.message.MessageMetaData_0_10;
+import org.apache.qpid.server.message.*;
 import org.apache.qpid.server.store.MessageMetaDataType;
 import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.store.StorableMessageMetaData;
 import org.apache.qpid.server.store.StoredMessage;
-import org.apache.qpid.server.store.TransactionLog;
 import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.transport.DeliveryProperties;
 import org.apache.qpid.transport.Header;
@@ -100,7 +98,7 @@
          */        
         MessageProperties msgProps_0_10 = createMessageProperties_0_10(bodySize);
         DeliveryProperties delProps_0_10 = createDeliveryProperties_0_10();
-        Header header_0_10 = new Header(msgProps_0_10, delProps_0_10);
+        Header header_0_10 = new Header(delProps_0_10, msgProps_0_10);
 
         MessageTransfer xfr_0_10 = new MessageTransfer("destination", MessageAcceptMode.EXPLICIT, 
                 MessageAcquireMode.PRE_ACQUIRED, header_0_10, completeContentBody_0_10);
@@ -162,7 +160,7 @@
 
         assertEquals("Message arrival time has changed", origArrivalTime_0_10, returnedMMD_0_10.getArrivalTime());
 
-        DeliveryProperties returnedDelProps_0_10 = returnedMMD_0_10.getHeader().get(DeliveryProperties.class);
+        DeliveryProperties returnedDelProps_0_10 = returnedMMD_0_10.getHeader().getDeliveryProperties();
         assertNotNull("DeliveryProperties were not returned", returnedDelProps_0_10);
         assertEquals("Immediate flag has changed", delProps_0_10.getImmediate(), returnedDelProps_0_10.getImmediate());
         assertEquals("Routing key has changed", delProps_0_10.getRoutingKey(), returnedDelProps_0_10.getRoutingKey());
@@ -170,7 +168,7 @@
         assertEquals("Message expiration has changed", delProps_0_10.getExpiration(), returnedDelProps_0_10.getExpiration());
         assertEquals("Message delivery priority has changed", delProps_0_10.getPriority(), returnedDelProps_0_10.getPriority());
 
-        MessageProperties returnedMsgProps = returnedMMD_0_10.getHeader().get(MessageProperties.class);
+        MessageProperties returnedMsgProps = returnedMMD_0_10.getHeader().getMessageProperties();
         assertNotNull("MessageProperties were not returned", returnedMsgProps);
         assertTrue("Message correlationID has changed", Arrays.equals(msgProps_0_10.getCorrelationId(), returnedMsgProps.getCorrelationId()));
         assertEquals("Message content length has changed", msgProps_0_10.getContentLength(), returnedMsgProps.getContentLength());
@@ -352,7 +350,7 @@
      */
     public void testTranCommit() throws Exception
     {
-        TransactionLog log = getVirtualHost().getTransactionLog();
+        MessageStore log = getVirtualHost().getMessageStore();
 
         BDBMessageStore bdbStore = assertBDBStore(log);
 
@@ -366,10 +364,10 @@
             }
         };
         
-        TransactionLog.Transaction txn = log.newTransaction();
+        MessageStore.Transaction txn = log.newTransaction();
         
-        txn.enqueueMessage(mockQueue, 1L);
-        txn.enqueueMessage(mockQueue, 5L);
+        txn.enqueueMessage(mockQueue, new MockMessage(1L));
+        txn.enqueueMessage(mockQueue, new MockMessage(5L));
         txn.commitTran();
 
         List<Long> enqueuedIds = bdbStore.getEnqueuedMessages(mockQueueName);
@@ -390,7 +388,7 @@
      */
     public void testTranRollbackBeforeCommit() throws Exception
     {
-        TransactionLog log = getVirtualHost().getTransactionLog();
+        MessageStore log = getVirtualHost().getMessageStore();
 
         BDBMessageStore bdbStore = assertBDBStore(log);
 
@@ -404,14 +402,14 @@
             }
         };
         
-        TransactionLog.Transaction txn = log.newTransaction();
+        MessageStore.Transaction txn = log.newTransaction();
         
-        txn.enqueueMessage(mockQueue, 21L);
+        txn.enqueueMessage(mockQueue, new MockMessage(21L));
         txn.abortTran();
         
         txn = log.newTransaction();
-        txn.enqueueMessage(mockQueue, 22L);
-        txn.enqueueMessage(mockQueue, 23L);
+        txn.enqueueMessage(mockQueue, new MockMessage(22L));
+        txn.enqueueMessage(mockQueue, new MockMessage(23L));
         txn.commitTran();
 
         List<Long> enqueuedIds = bdbStore.getEnqueuedMessages(mockQueueName);
@@ -431,7 +429,7 @@
      */
     public void testTranRollbackAfterCommit() throws Exception
     {
-        TransactionLog log = getVirtualHost().getTransactionLog();
+        MessageStore log = getVirtualHost().getMessageStore();
 
         BDBMessageStore bdbStore = assertBDBStore(log);
 
@@ -445,17 +443,17 @@
             }
         };
         
-        TransactionLog.Transaction txn = log.newTransaction();
+        MessageStore.Transaction txn = log.newTransaction();
         
-        txn.enqueueMessage(mockQueue, 30L);
+        txn.enqueueMessage(mockQueue, new MockMessage(30L));
         txn.commitTran();
 
         txn = log.newTransaction();
-        txn.enqueueMessage(mockQueue, 31L);
+        txn.enqueueMessage(mockQueue, new MockMessage(31L));
         txn.abortTran();
         
         txn = log.newTransaction();
-        txn.enqueueMessage(mockQueue, 32L);
+        txn.enqueueMessage(mockQueue, new MockMessage(32L));
         txn.commitTran();
         
         List<Long> enqueuedIds = bdbStore.getEnqueuedMessages(mockQueueName);
@@ -467,4 +465,73 @@
         assertEquals("Second Message is incorrect", 32L, val.longValue());
     }
 
+    private static class MockMessage implements ServerMessage, EnqueableMessage
+    {
+        private long _messageId;
+
+        public MockMessage(long messageId)
+        {
+            _messageId = messageId;
+        }
+
+        public String getRoutingKey()
+        {
+            return null;
+        }
+
+        public AMQMessageHeader getMessageHeader()
+        {
+            return null;
+        }
+
+        public StoredMessage getStoredMessage()
+        {
+            return null;
+        }
+
+        public boolean isPersistent()
+        {
+            return true;
+        }
+
+        public long getSize()
+        {
+            return 0;
+        }
+
+        public boolean isImmediate()
+        {
+            return false;
+        }
+
+        public long getExpiration()
+        {
+            return 0;
+        }
+
+        public MessageReference newReference()
+        {
+            return null;
+        }
+
+        public long getMessageNumber()
+        {
+            return _messageId;
+        }
+
+        public long getArrivalTime()
+        {
+            return 0;
+        }
+
+        public int getContent(ByteBuffer buf, int offset)
+        {
+            return 0;
+        }
+
+        public ByteBuffer getContent(int offset, int length)
+        {
+            return null;
+        }
+    }
 }
diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java
index 8e55e79..6d7cca5 100644
--- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java
+++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBUpgradeTest.java
@@ -52,7 +52,9 @@
 import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
 import org.apache.qpid.management.common.mbeans.ManagedQueue;
 import org.apache.qpid.server.message.MessageMetaData;
-import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.store.MessageStore;
+import org.apache.qpid.server.store.StoredMessage;
 import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.server.store.berkeleydb.keys.MessageContentKey_4;
 import org.apache.qpid.server.store.berkeleydb.tuples.MessageContentKeyTupleBindingFactory;
@@ -415,7 +417,7 @@
             ContentHeaderBody contentHeaderBody = new ContentHeaderBody(classForBasic, 1, props, bodySize);
 
             // add content entry to database
-            long messageId = store.getNewMessageId();
+            final long messageId = store.getNewMessageId();
             TupleBinding<MessageContentKey> contentKeyTB = new MessageContentKeyTupleBindingFactory(storeVersion).getInstance();
             MessageContentKey contentKey = null;
             if (storeVersion == VERSION_4)
@@ -451,9 +453,29 @@
                     return queueName.asString();
                 }
             };
-            TransactionLog log = (TransactionLog) store;
-            TransactionLog.Transaction txn = log.newTransaction();
-            txn.enqueueMessage(mockQueue, messageId);
+
+            EnqueableMessage mockMessage = new EnqueableMessage()
+            {
+    
+                public long getMessageNumber()
+                {
+                    return messageId;
+                }
+
+                public boolean isPersistent()
+                {
+                    return true;
+                }
+
+                public StoredMessage getStoredMessage()
+                {
+                    return null;
+                }
+            };
+
+            MessageStore log = (MessageStore) store;
+            MessageStore.Transaction txn = log.newTransaction();
+            txn.enqueueMessage(mockQueue, mockMessage);
             txn.commitTran();
         }
         finally
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java
index 593c161..b898e85 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/ManagementExchange.java
@@ -111,6 +111,11 @@
 
         }
 
+        public void enqueue(ServerMessage message, boolean sync, PostEnqueueAction action) throws AMQException
+        {
+            enqueue(message);
+        }
+
         public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException
         {
             enqueue(message);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java
index b98daf7..709b595 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFBrokerRequestCommand.java
@@ -21,6 +21,7 @@
 
 package org.apache.qpid.qmf;
 
+import org.apache.log4j.Logger;
 import org.apache.qpid.transport.codec.BBDecoder;
 import org.apache.qpid.transport.codec.BBEncoder;
 import org.apache.qpid.server.message.ServerMessage;
@@ -32,10 +33,14 @@
 import org.apache.qpid.management.common.mbeans.ManagedConnection;
 
 import java.util.ArrayList;
+import java.util.List;
 
 public class QMFBrokerRequestCommand extends QMFCommand
 {
 
+    private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf");
+
+
     public QMFBrokerRequestCommand(QMFCommandHeader header, BBDecoder buf)
     {
         super(header);
@@ -46,6 +51,8 @@
         String exchangeName = message.getMessageHeader().getReplyToExchange();
         String queueName = message.getMessageHeader().getReplyToRoutingKey();
 
+        _qmfLogger.debug("Execute: " + this);
+
         QMFCommand[] commands = new QMFCommand[2];
         commands[0] = new QMFBrokerResponseCommand(this, virtualHost);
         commands[1] = new QMFCommandCompletionCommand(this);
@@ -57,7 +64,7 @@
             QMFMessage responseMessage = new QMFMessage(queueName, cmd);
 
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage);
+            List<? extends BaseQueue> queues = exchange.route(responseMessage);
 
 
             for(BaseQueue q : queues)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java
index 26a27cf..64edc2f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFClassQueryCommand.java
@@ -21,6 +21,7 @@
 
 package org.apache.qpid.qmf;
 
+import org.apache.log4j.Logger;
 import org.apache.qpid.transport.codec.BBDecoder;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 import org.apache.qpid.server.message.ServerMessage;
@@ -31,9 +32,13 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 public class QMFClassQueryCommand extends QMFCommand
 {
+    private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf");
+
+
     private final String _package;
 
     public QMFClassQueryCommand(QMFCommandHeader header, BBDecoder decoder)
@@ -47,6 +52,8 @@
         String exchangeName = message.getMessageHeader().getReplyToExchange();
         String routingKey = message.getMessageHeader().getReplyToRoutingKey();
 
+        _qmfLogger.debug("Execute: " + this);
+
         IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry();
         QMFService service = appRegistry.getQMFService();
 
@@ -71,7 +78,7 @@
 
             Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName);
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage);
+            List<? extends BaseQueue> queues = exchange.route(responseMessage);
 
             for(BaseQueue q : queues)
             {
@@ -87,4 +94,12 @@
         }
     }
 
+
+    @Override
+    public String toString()
+    {
+        return "QMFClassQueryCommand{" +
+               "package='" + _package + '\'' +
+               '}';
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java
index f163e43..9a25201 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFCommandCompletionCommand.java
@@ -53,4 +53,13 @@
         encoder.writeInt32(_status.ordinal());
         encoder.writeStr8(_text);
     }
+
+    @Override
+    public String toString()
+    {
+        return "QMFCommandCompletionCommand{" +
+               "status=" + _status +
+               ",text='" + _text + '\'' +
+               '}';
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java
index 8e8cb55..c11e1a9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFGetQueryCommand.java
@@ -21,6 +21,7 @@
 
 package org.apache.qpid.qmf;
 
+import org.apache.log4j.Logger;
 import org.apache.qpid.transport.codec.BBDecoder;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 import org.apache.qpid.server.message.ServerMessage;
@@ -33,28 +34,22 @@
 
 public class QMFGetQueryCommand extends QMFCommand
 {
-    private Map<String, Object> _map;
 
+    private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf");
+
+    private String _className;
+    private String _packageName;
+    private UUID _objectId;
 
     public QMFGetQueryCommand(QMFCommandHeader header, BBDecoder decoder)
     {
         super(header);
 
-        _map = decoder.readMap();
-    }
-
-    public void process(VirtualHost virtualHost, ServerMessage message)
-    {
-        String exchangeName = message.getMessageHeader().getReplyToExchange();
-        String routingKey = message.getMessageHeader().getReplyToRoutingKey();
-
-        IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry();
-        QMFService service = appRegistry.getQMFService();
-
-        String className = (String) _map.get("_class");
-        String packageName = (String) _map.get("_package");
+        Map<String, Object> _map = decoder.readMap();
+        _className = (String) _map.get("_class");
+        _packageName = (String) _map.get("_package");
         byte[] objectIdBytes = (byte[]) _map.get("_objectId");
-        UUID objectId;
+
         if(objectIdBytes != null)
         {
             long msb = 0;
@@ -68,21 +63,34 @@
             {
                 lsb = (lsb << 8) | (objectIdBytes[i] & 0xff);
             }
-            objectId = new UUID(msb, lsb);
+            _objectId = new UUID(msb, lsb);
         }
         else
         {
-            objectId = null;
+            _objectId = null;
         }
 
+
+    }
+
+    public void process(VirtualHost virtualHost, ServerMessage message)
+    {
+        String exchangeName = message.getMessageHeader().getReplyToExchange();
+        String routingKey = message.getMessageHeader().getReplyToRoutingKey();
+
+        IApplicationRegistry appRegistry = virtualHost.getApplicationRegistry();
+        QMFService service = appRegistry.getQMFService();
+
+        _qmfLogger.debug("Execute: " + this);
+
         List<QMFCommand> commands = new ArrayList<QMFCommand>();
         final long sampleTime = System.currentTimeMillis() * 1000000l;
 
         Collection<QMFPackage> packages;
 
-        if(packageName != null && packageName.length() != 0)
+        if(_packageName != null && _packageName.length() != 0)
         {
-            QMFPackage qmfPackage = service.getPackage(packageName);
+            QMFPackage qmfPackage = service.getPackage(_packageName);
             if(qmfPackage == null)
             {
                 packages = Collections.EMPTY_LIST;
@@ -102,9 +110,9 @@
 
             Collection<QMFClass> qmfClasses;
 
-            if(className != null && className.length() != 0)
+            if(_className != null && _className.length() != 0)
             {
-                QMFClass qmfClass = qmfPackage.getQMFClass(className);
+                QMFClass qmfClass = qmfPackage.getQMFClass(_className);
                 if(qmfClass == null)
                 {
                     qmfClasses = Collections.EMPTY_LIST;
@@ -124,9 +132,9 @@
             {
                 Collection<QMFObject> objects;
 
-                if(objectId != null)
+                if(_objectId != null)
                 {
-                    QMFObject obj = service.getObjectById(qmfClass, objectId);
+                    QMFObject obj = service.getObjectById(qmfClass, _objectId);
                     if(obj == null)
                     {
                         objects = Collections.EMPTY_LIST;
@@ -158,12 +166,12 @@
         for(QMFCommand cmd : commands)
         {
 
-
+            _qmfLogger.debug("Respond: " + cmd);
             QMFMessage responseMessage = new QMFMessage(routingKey, cmd);
 
             Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName);
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage);
+            List<? extends BaseQueue> queues = exchange.route(responseMessage);
 
             for(BaseQueue q : queues)
             {
@@ -179,4 +187,13 @@
         }
     }
 
+    @Override
+    public String toString()
+    {
+        return "QMFGetQueryCommand{" +
+               "packageName='" + _packageName + '\'' +
+               ", className='" + _className + '\'' +
+               ", objectId=" + _objectId +
+               '}';
+    }
 }
\ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java
index 3f6290d..3248a5a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMessage.java
@@ -21,14 +21,17 @@
 
 package org.apache.qpid.qmf;
 
+import org.apache.commons.lang.NotImplementedException;
+import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.server.configuration.SessionConfig;
 import org.apache.qpid.server.message.*;
+import org.apache.qpid.server.store.StoredMessage;
 import org.apache.qpid.transport.codec.BBEncoder;
 
 import java.nio.ByteBuffer;
 import java.util.Set;
 
-public class QMFMessage implements ServerMessage<QMFMessage>, InboundMessage, AMQMessageHeader
+public class QMFMessage implements ServerMessage, InboundMessage, AMQMessageHeader
 {
 
     private ByteBuffer _content;
@@ -59,11 +62,21 @@
         return _routingKey;
     }
 
+    public AMQShortString getRoutingKeyShortString()
+    {
+        return AMQShortString.valueOf(_routingKey);
+    }
+
     public AMQMessageHeader getMessageHeader()
     {
         return this;
     }
 
+    public StoredMessage getStoredMessage()
+    {
+        throw new NotImplementedException();
+    }
+
     public boolean isPersistent()
     {
         return false;
@@ -159,9 +172,9 @@
         return new QMFMessageReference(this);
     }
 
-    public Long getMessageNumber()
+    public long getMessageNumber()
     {
-        return null;
+        return 0l;
     }
 
     public long getArrivalTime()
@@ -172,9 +185,9 @@
     public int getContent(ByteBuffer buf, int offset)
     {
         ByteBuffer src = _content.duplicate();
-        _content.position(offset);
-        _content = _content.slice();
-        int len = _content.remaining();
+        src.position(offset);
+        src = src.slice();
+        int len = src.remaining();
         if(len > buf.remaining())
         {
             len = buf.remaining();
@@ -185,6 +198,16 @@
         return len;
     }
 
+
+    public ByteBuffer getContent(int offset, int size)
+    {
+        ByteBuffer src = _content.duplicate();
+        src.position(offset);
+        src = src.slice();
+        src.limit(size);
+        return src;
+    }
+
     private static class QMFMessageReference extends MessageReference<QMFMessage>
     {
         public QMFMessageReference(QMFMessage message)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java
index cf27e4b..4001a2a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFMethodRequestCommand.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.qmf;
 
+import org.apache.log4j.Logger;
 import org.apache.qpid.transport.codec.BBDecoder;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 import org.apache.qpid.server.message.ServerMessage;
@@ -27,11 +28,14 @@
 import org.apache.qpid.server.queue.BaseQueue;
 import org.apache.qpid.AMQException;
 
+import java.util.List;
 import java.util.UUID;
 import java.util.ArrayList;
 
 public class QMFMethodRequestCommand extends QMFCommand
 {
+    private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf");
+
     private QMFMethodInvocation _methodInstance;
     private QMFObject _object;
 
@@ -58,6 +62,9 @@
         String queueName = message.getMessageHeader().getReplyToRoutingKey();
 
         QMFCommand[] commands = new QMFCommand[2];
+
+        _qmfLogger.debug("Execute: " + _methodInstance + " on " + _object);
+
         commands[0] = _methodInstance.execute(_object, this);
         commands[1] = new QMFCommandCompletionCommand(this);
 
@@ -68,7 +75,7 @@
             QMFMessage responseMessage = new QMFMessage(queueName, cmd);
 
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage);
+            List<? extends BaseQueue> queues = exchange.route(responseMessage);
 
 
             for(BaseQueue q : queues)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java
index d126717..631bd3c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFObject.java
@@ -73,4 +73,9 @@
     abstract public QMFCommand asInstrumentInfoCmd(long sampleTime);
     abstract public QMFCommand asGetQueryResponseCmd(final QMFGetQueryCommand queryCommand, long sampleTime);
 
+    @Override
+    public String toString()
+    {
+        return _delegate.toString();
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java
index 6defd08..9cacbaf 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFPackageQueryCommand.java
@@ -21,6 +21,7 @@
 
 package org.apache.qpid.qmf;
 
+import org.apache.log4j.Logger;
 import org.apache.qpid.transport.codec.BBDecoder;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 import org.apache.qpid.server.message.ServerMessage;
@@ -31,9 +32,13 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 public class QMFPackageQueryCommand extends QMFCommand
 {
+
+    private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf");
+
     public QMFPackageQueryCommand(QMFCommandHeader header, BBDecoder decoder)
     {
         super(header);
@@ -52,6 +57,8 @@
         
         QMFCommand[] commands = new QMFCommand[ supportedSchemas.size() + 1 ];
 
+        _qmfLogger.debug("Exectuting " + this);
+        
         int i = 0;
         for(QMFPackage p : supportedSchemas)
         {
@@ -67,7 +74,7 @@
 
             Exchange exchange = virtualHost.getExchangeRegistry().getExchange(exchangeName);
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage);
+            List<? extends BaseQueue> queues = exchange.route(responseMessage);
 
 
             for(BaseQueue q : queues)
@@ -83,4 +90,9 @@
             }
         }
     }
+    
+    public String toString()
+    {
+        return "QMFPackageQueryCommand";
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java
index 3141676..a1260ed 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFSchemaRequestCommand.java
@@ -21,6 +21,7 @@
 
 package org.apache.qpid.qmf;
 
+import org.apache.log4j.Logger;
 import org.apache.qpid.transport.codec.BBDecoder;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 import org.apache.qpid.server.message.ServerMessage;
@@ -31,9 +32,12 @@
 
 import java.util.Collection;
 import java.util.ArrayList;
+import java.util.List;
 
 public class QMFSchemaRequestCommand extends QMFCommand
 {
+    private static final Logger _qmfLogger = Logger.getLogger("qpid.qmf");
+
     private final String _packageName;
     private final String _className;
     private final byte[] _hash;
@@ -48,6 +52,8 @@
 
     public void process(VirtualHost virtualHost, ServerMessage message)
     {
+        _qmfLogger.debug("Execute: " + this);
+
         String exchangeName = message.getMessageHeader().getReplyToExchange();
         String routingKey = message.getMessageHeader().getReplyToRoutingKey();
 
@@ -70,7 +76,7 @@
             QMFMessage responseMessage = new QMFMessage(routingKey, cmd);
 
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(responseMessage);
+            List<? extends BaseQueue> queues = exchange.route(responseMessage);
 
             for(BaseQueue q : queues)
             {
@@ -85,4 +91,13 @@
             }
         }
     }
+
+    @Override
+    public String toString()
+    {
+        return "QMFSchemaRequestCommand{" +
+               " packageName='" + _packageName + '\'' +
+               ", className='" + _className + '\'' +
+               '}';
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
index 6abef6f..27345f0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/qmf/QMFService.java
@@ -410,7 +410,10 @@
         ConcurrentHashMap<UUID, QMFObject> map = _managedObjectsById.get(qmfclass);
         if(map != null)
         {
-            return map.get(id);
+
+            UUID key = new UUID(id.getMostSignificantBits() & (0xFFFl << 48), id.getLeastSignificantBits());
+            return map.get(key);
+
         }
         else
         {
@@ -604,6 +607,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class BrokerDelegate implements BrokerSchema.BrokerDelegate
@@ -762,6 +770,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class VhostDelegate implements BrokerSchema.VhostDelegate
@@ -797,6 +810,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class ExchangeDelegate implements BrokerSchema.ExchangeDelegate
@@ -923,6 +941,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class QueueDelegate implements BrokerSchema.QueueDelegate
@@ -1163,6 +1186,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class BindingDelegate implements BrokerSchema.BindingDelegate
@@ -1214,6 +1242,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class ConnectionDelegate implements BrokerSchema.ConnectionDelegate
@@ -1352,6 +1385,12 @@
             // TODO
             return 0;
         }
+
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class SessionDelegate implements BrokerSchema.SessionDelegate
@@ -1476,6 +1515,11 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
     private class SubscriptionDelegate implements BrokerSchema.SubscriptionDelegate
@@ -1542,93 +1586,103 @@
         {
             return _obj.getCreateTime();
         }
+
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
-        private class BridgeDelegate implements BrokerSchema.BridgeDelegate
+    private class BridgeDelegate implements BrokerSchema.BridgeDelegate
+    {
+        private final BridgeConfig _obj;
+
+        private BridgeDelegate(final BridgeConfig obj)
         {
-            private final BridgeConfig _obj;
-
-            private BridgeDelegate(final BridgeConfig obj)
-            {
-                _obj = obj;
-            }
-
-            public BrokerSchema.LinkObject getLinkRef()
-            {
-                return (BrokerSchema.LinkObject) adapt(_obj.getLink());
-            }
-
-            public Integer getChannelId()
-            {
-                return _obj.getChannelId();
-            }
-
-            public Boolean getDurable()
-            {
-                return _obj.isDurable();
-            }
-
-            public String getSrc()
-            {
-                return _obj.getSource();
-            }
-
-            public String getDest()
-            {
-                return _obj.getDestination();
-            }
-
-            public String getKey()
-            {
-                return _obj.getKey();
-            }
-
-            public Boolean getSrcIsQueue()
-            {
-                return _obj.isQueueBridge();
-            }
-
-            public Boolean getSrcIsLocal()
-            {
-                return _obj.isLocalSource();
-            }
-
-            public String getTag()
-            {
-                return _obj.getTag();
-            }
-
-            public String getExcludes()
-            {
-                return _obj.getExcludes();
-            }
-
-            public Boolean getDynamic()
-            {
-                return _obj.isDynamic();
-            }
-
-            public Integer getSync()
-            {
-                return _obj.getAckBatching();
-            }
-
-            public BrokerSchema.BridgeClass.CloseMethodResponseCommand close(final BrokerSchema.BridgeClass.CloseMethodResponseCommandFactory factory)
-            {
-                return null;
-            }
-
-            public UUID getId()
-            {
-                return _obj.getId();
-            }
-
-            public long getCreateTime()
-            {
-                return _obj.getCreateTime();
-            }
+            _obj = obj;
         }
 
+        public BrokerSchema.LinkObject getLinkRef()
+        {
+            return (BrokerSchema.LinkObject) adapt(_obj.getLink());
+        }
+
+        public Integer getChannelId()
+        {
+            return _obj.getChannelId();
+        }
+
+        public Boolean getDurable()
+        {
+            return _obj.isDurable();
+        }
+
+        public String getSrc()
+        {
+            return _obj.getSource();
+        }
+
+        public String getDest()
+        {
+            return _obj.getDestination();
+        }
+
+        public String getKey()
+        {
+            return _obj.getKey();
+        }
+
+        public Boolean getSrcIsQueue()
+        {
+            return _obj.isQueueBridge();
+        }
+
+        public Boolean getSrcIsLocal()
+        {
+            return _obj.isLocalSource();
+        }
+
+        public String getTag()
+        {
+            return _obj.getTag();
+        }
+
+        public String getExcludes()
+        {
+            return _obj.getExcludes();
+        }
+
+        public Boolean getDynamic()
+        {
+            return _obj.isDynamic();
+        }
+
+        public Integer getSync()
+        {
+            return _obj.getAckBatching();
+        }
+
+        public BrokerSchema.BridgeClass.CloseMethodResponseCommand close(final BrokerSchema.BridgeClass.CloseMethodResponseCommandFactory factory)
+        {
+            return null;
+        }
+
+        public UUID getId()
+        {
+            return _obj.getId();
+        }
+
+        public long getCreateTime()
+        {
+            return _obj.getCreateTime();
+        }
+        
+        public String toString()
+        {
+            return _obj.toString();
+        }
+    }
+
     private class LinkDelegate implements BrokerSchema.LinkDelegate
     {
         private final LinkConfig _obj;
@@ -1665,14 +1719,12 @@
 
         public String getState()
         {
-            // TODO
-            return "";
+            return _obj.getState();
         }
 
         public String getLastError()
         {
-            // TODO
-            return "";
+            return _obj.getLastError();
         }
 
         public BrokerSchema.LinkClass.CloseMethodResponseCommand close(final BrokerSchema.LinkClass.CloseMethodResponseCommandFactory factory)
@@ -1706,6 +1758,12 @@
         {
             return _obj.getCreateTime();
         }
+
+        @Override
+        public String toString()
+        {
+            return _obj.toString();
+        }
     }
 
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
index 30d6204..873c846 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/AMQChannel.java
@@ -96,7 +96,7 @@
 
 public class AMQChannel implements SessionConfig, AMQSessionModel
 {
-    public static final int DEFAULT_PREFETCH = 5000;
+    public static final int DEFAULT_PREFETCH = 4096;
 
     private static final Logger _logger = Logger.getLogger(AMQChannel.class);
 
@@ -167,6 +167,8 @@
     private final UUID _id;
     private long _createTime = System.currentTimeMillis();
 
+    private final ClientDeliveryMethod _clientDeliveryMethod;
+
     public AMQChannel(AMQProtocolSession session, int channelId, MessageStore messageStore)
             throws AMQException
     {
@@ -184,6 +186,8 @@
 
         // by default the session is non-transactional
         _transaction = new AutoCommitTransaction(_messageStore);
+
+         _clientDeliveryMethod = session.createDeliveryMethod(_channelId);
     }
 
     public ConfigStore getConfigStore()
@@ -206,6 +210,11 @@
         return !(_transaction instanceof AutoCommitTransaction);
     }
 
+    public void receivedComplete()
+    {
+    }
+
+
     public boolean inTransaction()
     {
         return isTransactional() && _txnUpdateTime.get() > 0 && _transaction.getTransactionStartTime() > 0;
@@ -285,7 +294,7 @@
             _currentMessage.setExpiration();
 
 
-            MessageMetaData mmd = _currentMessage.headersReceived();
+            MessageMetaData mmd = _currentMessage.headersReceived(getProtocolSession().getLastReceivedTime());
             final StoredMessage<MessageMetaData> handle = _messageStore.addMessage(mmd);
             _currentMessage.setStoredMessage(handle);
 
@@ -317,8 +326,7 @@
         {
             try
             {
-                _currentMessage.getStoredMessage().flushToStore();
-                final ArrayList<? extends BaseQueue> destinationQueues = _currentMessage.getDestinationQueues();
+                final List<? extends BaseQueue> destinationQueues = _currentMessage.getDestinationQueues();
 
                 if(!checkMessageUserId(_currentMessage.getContentHeader()))
                 {
@@ -340,11 +348,13 @@
                     }
                     else
                     {
-                        _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues, isTransactional()));
+                        _transaction.enqueue(destinationQueues, _currentMessage, new MessageDeliveryAction(_currentMessage, destinationQueues), getProtocolSession().getLastReceivedTime());
                         incrementOutstandingTxnsIfNecessary();
 			            updateTransactionalActivity();
                     }
                 }
+                _currentMessage.getStoredMessage().flushToStore();
+
             }
             finally
             {
@@ -858,10 +868,8 @@
     private Collection<QueueEntry> getAckedMessages(long deliveryTag, boolean multiple)
     {
 
-        Map<Long, QueueEntry> ackedMessageMap = new LinkedHashMap<Long,QueueEntry>();
-        _unacknowledgedMessageMap.collect(deliveryTag, multiple, ackedMessageMap);
-        _unacknowledgedMessageMap.remove(ackedMessageMap);
-        return ackedMessageMap.values();
+        return _unacknowledgedMessageMap.acknowledge(deliveryTag, multiple);
+
     }
 
     /**
@@ -950,12 +958,17 @@
 
     public void commit() throws AMQException
     {
+        commit(null);
+    }
+    public void commit(Runnable immediateAction) throws AMQException
+    {
+
         if (!isTransactional())
         {
             throw new AMQException("Fatal error: commit called on non-transactional channel");
         }
 
-        _transaction.commit();
+        _transaction.commit(immediateAction);
 
         _txnCommits.incrementAndGet();
         _txnStarts.incrementAndGet();
@@ -1034,7 +1047,7 @@
     {
         if (isTransactional())
         {
-            _txnUpdateTime.set(System.currentTimeMillis());
+            _txnUpdateTime.set(getProtocolSession().getLastReceivedTime());
         }
     }
 
@@ -1080,21 +1093,6 @@
         return _messageStore;
     }
 
-    private final ClientDeliveryMethod _clientDeliveryMethod = new ClientDeliveryMethod()
-        {
-
-            public void deliverToClient(final Subscription sub, final QueueEntry entry, final long deliveryTag)
-                    throws AMQException
-            {
-                _session.registerMessageDelivered(entry.getMessage().getSize());
-                getProtocolSession().getProtocolOutputConverter().writeDeliver(entry, getChannelId(),
-                                                                               deliveryTag,
-                                                                               ((SubscriptionImpl)sub).getConsumerTag());
-                entry.incrementDeliveryCount();
-            }
-
-        };
-
     public ClientDeliveryMethod getClientDeliveryMethod()
     {
         return _clientDeliveryMethod;
@@ -1160,11 +1158,10 @@
     private class MessageDeliveryAction implements ServerTransaction.Action
     {
         private IncomingMessage _incommingMessage;
-        private ArrayList<? extends BaseQueue> _destinationQueues;
+        private List<? extends BaseQueue> _destinationQueues;
 
         public MessageDeliveryAction(IncomingMessage currentMessage,
-                                     ArrayList<? extends BaseQueue> destinationQueues,
-                                     boolean transactional)
+                                     List<? extends BaseQueue> destinationQueues)
         {
             _incommingMessage = currentMessage;
             _destinationQueues = destinationQueues;
@@ -1179,8 +1176,10 @@
                 final AMQMessage amqMessage = createAMQMessage(_incommingMessage);
                 MessageReference ref = amqMessage.newReference();
 
-                for(final BaseQueue queue : _destinationQueues)
+                for(int i = 0; i < _destinationQueues.size(); i++)
                 {
+                    BaseQueue queue = _destinationQueues.get(i);
+
                     BaseQueue.PostEnqueueAction action;
 
                     if(immediate)
@@ -1192,7 +1191,7 @@
                         action = null;
                     }
 
-                    queue.enqueue(amqMessage, action);
+                    queue.enqueue(amqMessage, isTransactional(), action);
 
                     if(queue instanceof AMQQueue)
                     {
@@ -1200,6 +1199,8 @@
                     }
 
                 }
+
+                _incommingMessage.getStoredMessage().flushToStore();
                 ref.release();
             }
             catch (AMQException e)
@@ -1541,7 +1542,7 @@
 
             final InboundMessage m = new InboundMessageAdapter(rejectedQueueEntry);
 
-            final ArrayList<? extends BaseQueue> destinationQueues = altExchange.route(m);
+            final List<? extends BaseQueue> destinationQueues = altExchange.route(m);
 
             if (destinationQueues == null || destinationQueues.isEmpty())
             {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java
index 9da02e0..9765636 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ExtractResendAndRequeue.java
@@ -22,8 +22,8 @@
 
 import org.apache.qpid.server.ack.UnacknowledgedMessageMap;
 import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.store.TransactionLog;
 import org.apache.qpid.server.txn.ServerTransaction;
 import org.apache.qpid.server.txn.AutoCommitTransaction;
 import org.apache.qpid.AMQException;
@@ -39,13 +39,13 @@
     private final Map<Long, QueueEntry> _msgToResend;
     private final boolean _requeueIfUnabletoResend;
     private final UnacknowledgedMessageMap _unacknowledgedMessageMap;
-    private final TransactionLog _transactionLog;
+    private final MessageStore _transactionLog;
 
     public ExtractResendAndRequeue(UnacknowledgedMessageMap unacknowledgedMessageMap,
                                    Map<Long, QueueEntry> msgToRequeue,
                                    Map<Long, QueueEntry> msgToResend,
                                    boolean requeueIfUnabletoResend,
-                                   TransactionLog txnLog)
+                                   MessageStore txnLog)
     {
         _unacknowledgedMessageMap = unacknowledgedMessageMap;
         _msgToRequeue = msgToRequeue;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java
index 0c038c7..2bfdd93 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java
@@ -27,6 +27,7 @@
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.PosixParser;
+import org.apache.log4j.Logger;
 import org.apache.qpid.server.Broker.InitException;
 import org.apache.qpid.server.registry.ApplicationRegistry;
 
@@ -230,11 +231,77 @@
             {
                 parsePortArray(options, commandLine.getOptionValues(pe.getExcludeName()), pe);
             }
-        }
+        }                
+        
+        setExceptionHandler();
         
         startBroker(options);
     }
 
+    protected void setExceptionHandler()
+    {
+        Thread.UncaughtExceptionHandler handler = null;
+        String handlerClass = System.getProperty("qpid.broker.exceptionHandler");
+        if(handlerClass != null)
+        {
+            try
+            {
+                handler = (Thread.UncaughtExceptionHandler) Class.forName(handlerClass).newInstance();
+            }
+            catch (ClassNotFoundException e)
+            {
+                
+            }
+            catch (InstantiationException e)
+            {
+                
+            }
+            catch (IllegalAccessException e)
+            {
+                
+            }
+            catch (ClassCastException e)
+            {
+
+            }
+        }
+        
+        if(handler == null)
+        {
+            handler =
+                new Thread.UncaughtExceptionHandler()
+                {
+                    public void uncaughtException(final Thread t, final Throwable e)
+                    {
+                        try
+                        {
+                            System.err.println("########################################################################");
+                            System.err.println("#");
+                            System.err.print("# Unhandled Exception ");
+                            System.err.print(e.toString());
+                            System.err.print(" in Thread ");
+                            System.err.println(t.getName());
+                            System.err.println("#");
+                            System.err.println("# Exiting");
+                            System.err.println("#");
+                            System.err.println("########################################################################");
+                            e.printStackTrace(System.err);
+
+                            Logger logger = Logger.getLogger("org.apache.qpid.server.Main");
+                            logger.error("Uncaught exception, shutting down.", e);
+                        }
+                        finally
+                        {
+                            Runtime.getRuntime().halt(1);
+                        }
+
+                    }
+                };
+
+            Thread.setDefaultUncaughtExceptionHandler(handler);
+        } 
+    }
+
     protected void startBroker(final BrokerOptions options) throws Exception
     {
         Broker broker = new Broker();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
index 3bad73d..f4b4932 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMap.java
@@ -46,10 +46,6 @@
 
     void add(long deliveryTag, QueueEntry message);
 
-    void collect(long deliveryTag, boolean multiple, Map<Long, QueueEntry> msgs);
-
-    void remove(Map<Long,QueueEntry> msgs);
-
     QueueEntry remove(long deliveryTag);
 
     Collection<QueueEntry> cancelAllMessages();
@@ -67,6 +63,8 @@
      */
     Set<Long> getDeliveryTags();
 
+    Collection<QueueEntry> acknowledge(long deliveryTag, boolean multiple);
+
 }
 
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
index d920d97..6a5d863 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/ack/UnacknowledgedMessageMapImpl.java
@@ -157,6 +157,14 @@
         }
     }
 
+    public Collection<QueueEntry> acknowledge(long deliveryTag, boolean multiple)
+    {
+        Map<Long, QueueEntry> ackedMessageMap = new LinkedHashMap<Long,QueueEntry>();
+        collect(deliveryTag, multiple, ackedMessageMap);
+        remove(ackedMessageMap);
+        return ackedMessageMap.values();
+    }
+
     private void collect(long key, Map<Long, QueueEntry> msgs)
     {
         synchronized (_lock)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java
index 60c9a86..48f85d9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/binding/Binding.java
@@ -115,4 +115,9 @@
         return result;
     }
 
+    public String toString()
+    {
+        return "Binding{bindingKey="+_bindingKey+", exchange="+_exchange+", queue="+_queue+"}";
+    }
+
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java
index 0e03e33..4e031f0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ConfigStore.java
@@ -40,7 +40,10 @@
     private AtomicReference<SystemConfig> _root = new AtomicReference<SystemConfig>(null);
 
     private final AtomicLong _objectIdSource = new AtomicLong(0l);
+    private final AtomicLong _persistentObjectIdSource = new AtomicLong(0l);
 
+    // TODO - should load/increment this on broker startup
+    private long _sequenceNumber = 1L;
 
     public enum Event
     {
@@ -167,9 +170,23 @@
 
     public UUID createId()
     {
-        return new UUID(0l, _objectIdSource.getAndIncrement());
+        return new UUID(((_sequenceNumber & 0xFFFl)<<48), _objectIdSource.incrementAndGet());
     }
 
+    public UUID createPersistentId()
+    {
+        return new UUID(0L, _persistentObjectIdSource.incrementAndGet());
+    }
+    
+    public void persistentIdInUse(UUID id)
+    {
+        long lsb = id.getLeastSignificantBits();
+        long currentId;
+        while((currentId = _persistentObjectIdSource.get()) < lsb)
+        {
+            _persistentObjectIdSource.compareAndSet(currentId, lsb);
+        }
+    }
 
     public SystemConfig getRoot()
     {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java
index 5a6159d..0b3a907 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/LinkConfig.java
@@ -54,4 +54,8 @@
                       String src,
                       String dest,
                       String key, String tag, String excludes);
+
+    String getState();
+
+    String getLastError();
 }
\ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
index 4b42e39..d3b8964 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/ServerConfiguration.java
@@ -89,7 +89,6 @@
         envVarMap.put("QPID_PORT", "connector.port");
         envVarMap.put("QPID_ENABLEDIRECTBUFFERS", "advanced.enableDirectBuffers");
         envVarMap.put("QPID_SSLPORT", "connector.ssl.port");
-        envVarMap.put("QPID_WRITEBIASED", "advanced.useWriteBiasedPool");
         envVarMap.put("QPID_JMXPORT_REGISTRYSERVER", MGMT_JMXPORT_REGISTRYSERVER);
         envVarMap.put("QPID_JMXPORT_CONNECTORSERVER", MGMT_JMXPORT_CONNECTORSERVER);
         envVarMap.put("QPID_FRAMESIZE", "advanced.framesize");
@@ -736,11 +735,6 @@
         return getStringValue("connector.ssl.certType", "SunX509");
     }
 
-    public boolean getUseBiasedWrites()
-    {
-        return getBooleanValue("advanced.useWriteBiasedPool");
-    }
-
     public String getDefaultVirtualHost()
     {
         return getStringValue("virtualhosts.default");
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
index d693c69..5ff90b3 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
@@ -351,11 +351,11 @@
 
 
 
-    public final ArrayList<? extends BaseQueue> route(final InboundMessage message)
+    public final List<? extends BaseQueue> route(final InboundMessage message)
     {
         _receivedMessageCount.incrementAndGet();
         _receivedMessageSize.addAndGet(message.getSize());
-        final ArrayList<? extends BaseQueue> queues = doRoute(message);
+        final List<? extends BaseQueue> queues = doRoute(message);
         if(!queues.isEmpty())
         {
             _routedMessageCount.incrementAndGet();
@@ -364,7 +364,7 @@
         return queues;
     }
 
-    protected abstract ArrayList<? extends BaseQueue> doRoute(final InboundMessage message);
+    protected abstract List<? extends BaseQueue> doRoute(final InboundMessage message);
 
     public long getMsgReceives()
     {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
index cb0d8ec..8c0a500 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/DirectExchange.java
@@ -34,6 +34,8 @@
 
 import javax.management.JMException;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 
@@ -41,8 +43,52 @@
 {
     private static final Logger _logger = Logger.getLogger(DirectExchange.class);
 
-    private final ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>> _bindingsByKey =
-            new ConcurrentHashMap<String, CopyOnWriteArraySet<Binding>>();
+    private static final class BindingSet
+    {
+        private CopyOnWriteArraySet<Binding> _bindings = new CopyOnWriteArraySet<Binding>();
+        private List<BaseQueue> _queues = new ArrayList<BaseQueue>();
+
+        public synchronized void addBinding(Binding binding)
+        {
+            _bindings.add(binding);
+            recalculateQueues();
+        }
+
+
+        public synchronized void removeBinding(Binding binding)
+        {
+            _bindings.remove(binding);
+            recalculateQueues();
+        }
+
+        private void recalculateQueues()
+        {
+            List<BaseQueue> queues = new ArrayList<BaseQueue>(_bindings.size());
+
+            for(Binding b : _bindings)
+            {
+                if(!queues.contains(b.getQueue()))
+                {
+                    queues.add(b.getQueue());
+                }
+            }
+            _queues = queues;
+        }
+
+
+        public List<BaseQueue> getQueues()
+        {
+            return _queues;
+        }
+
+        public CopyOnWriteArraySet<Binding> getBindings()
+        {
+            return _bindings;
+        }
+    }
+
+    private final ConcurrentHashMap<String, BindingSet> _bindingsByKey =
+            new ConcurrentHashMap<String, BindingSet>();
 
     public static final ExchangeType<DirectExchange> TYPE = new ExchangeType<DirectExchange>()
     {
@@ -91,33 +137,20 @@
     }
 
 
-    public ArrayList<? extends BaseQueue> doRoute(InboundMessage payload)
+    public List<? extends BaseQueue> doRoute(InboundMessage payload)
     {
 
         final String routingKey = payload.getRoutingKey();
 
-        CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(routingKey == null ? "" : routingKey);
+        BindingSet bindings = _bindingsByKey.get(routingKey == null ? "" : routingKey);
 
         if(bindings != null)
         {
-            final ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>(bindings.size());
-
-            for(Binding binding : bindings)
-            {
-                queues.add(binding.getQueue());
-                binding.incrementMatches();
-            }
-
-            if (_logger.isDebugEnabled())
-            {
-                _logger.debug("Publishing message to queue " + queues);
-            }
-
-            return queues;
+            return bindings.getQueues();
         }
         else
         {
-            return new ArrayList<BaseQueue>(0); 
+            return Collections.emptyList();
         }
 
 
@@ -132,16 +165,10 @@
     public boolean isBound(AMQShortString routingKey, AMQQueue queue)
     {
         String bindingKey = (routingKey == null) ? "" : routingKey.toString();
-        CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey);
+        BindingSet bindings = _bindingsByKey.get(bindingKey);
         if(bindings != null)
         {
-            for(Binding binding : bindings)
-            {
-                if(binding.getQueue().equals(queue))
-                {
-                    return true;
-                }
-            }
+            return bindings.getQueues().contains(queue);
         }
         return false;
 
@@ -150,22 +177,20 @@
     public boolean isBound(AMQShortString routingKey)
     {
         String bindingKey = (routingKey == null) ? "" : routingKey.toString();
-        CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey);
-        return bindings != null && !bindings.isEmpty();
+        BindingSet bindings = _bindingsByKey.get(bindingKey);
+        return bindings != null && !bindings.getQueues().isEmpty();
     }
 
     public boolean isBound(AMQQueue queue)
     {
 
-        for (CopyOnWriteArraySet<Binding> bindings : _bindingsByKey.values())
+        for (BindingSet bindings : _bindingsByKey.values())
         {
-            for(Binding binding : bindings)
+            if(bindings.getQueues().contains(queue))
             {
-                if(binding.getQueue().equals(queue))
-                {
-                    return true;
-                }
+                return true;
             }
+
         }
         return false;
     }
@@ -184,19 +209,19 @@
         assert queue != null;
         assert routingKey != null;
 
-        CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(bindingKey);
+        BindingSet bindings = _bindingsByKey.get(bindingKey);
 
         if(bindings == null)
         {
-            bindings = new CopyOnWriteArraySet<Binding>();
-            CopyOnWriteArraySet<Binding> newBindings;
+            bindings = new BindingSet();
+            BindingSet newBindings;
             if((newBindings = _bindingsByKey.putIfAbsent(bindingKey, bindings)) != null)
             {
                 bindings = newBindings;
             }
         }
 
-        bindings.add(binding);
+        bindings.addBinding(binding);
 
     }
 
@@ -204,10 +229,10 @@
     {
         assert binding != null;
 
-        CopyOnWriteArraySet<Binding> bindings = _bindingsByKey.get(binding.getBindingKey());
+        BindingSet bindings = _bindingsByKey.get(binding.getBindingKey());
         if(bindings != null)
         {
-            bindings.remove(binding);
+            bindings.removeBinding(binding);
         }
 
     }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
index 29a3611..29c354f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/Exchange.java
@@ -36,6 +36,7 @@
 import javax.management.JMException;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 
 public interface Exchange extends ExchangeReferrer, ExchangeConfig
 {
@@ -70,7 +71,7 @@
      *
      * @return list of queues to which to route the message.
      */
-    ArrayList<? extends BaseQueue> route(InboundMessage message);
+    List<? extends BaseQueue> route(InboundMessage message);
 
 
     /**
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
index e523eb2..3a8a86e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/TopicExchange.java
@@ -37,8 +37,11 @@
 import org.apache.qpid.server.message.InboundMessage;
 
 import javax.management.JMException;
+import java.sql.Array;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
 import java.lang.ref.WeakReference;
 
 public class TopicExchange extends AbstractExchange
@@ -77,8 +80,6 @@
 
     private static final Logger _logger = Logger.getLogger(TopicExchange.class);
 
-
-
     private final TopicParser _parser = new TopicParser();
 
     private final Map<AMQShortString, TopicExchangeResult> _topicExchangeResults =
@@ -175,7 +176,6 @@
             _bindings.put(binding, args);
         }
 
-
     }
 
     private JMSSelectorFilter createSelectorFilter(final FieldTable args) throws AMQInvalidArgumentException
@@ -201,14 +201,23 @@
     public ArrayList<BaseQueue> doRoute(InboundMessage payload)
     {
 
-        final AMQShortString routingKey = payload.getRoutingKey() == null
+        final AMQShortString routingKey = payload.getRoutingKeyShortString() == null
                                           ? AMQShortString.EMPTY_STRING
-                                          : new AMQShortString(payload.getRoutingKey());
+                                          : payload.getRoutingKeyShortString();
 
-        // The copy here is unfortunate, but not too bad relevant to the amount of
-        // things created and copied in getMatchedQueues
-        ArrayList<BaseQueue> queues = new ArrayList<BaseQueue>();
-        queues.addAll(getMatchedQueues(payload, routingKey));
+        final Collection<AMQQueue> matchedQueues = getMatchedQueues(payload, routingKey);
+
+        ArrayList<BaseQueue> queues;
+
+        if(matchedQueues.getClass() == ArrayList.class)
+        {
+            queues = (ArrayList) matchedQueues;
+        }
+        else
+        {
+            queues = new ArrayList<BaseQueue>();
+            queues.addAll(matchedQueues);
+        }
 
         if(queues == null || queues.isEmpty())
         {
@@ -325,25 +334,28 @@
     {
 
         Collection<TopicMatcherResult> results = _parser.parse(routingKey);
-        if(results.isEmpty())
+        switch(results.size())
         {
-            return Collections.EMPTY_SET;
-        }
-        else
-        {
-            Collection<AMQQueue> queues = results.size() == 1 ? null : new HashSet<AMQQueue>();
-            for(TopicMatcherResult result : results)
-            {
-                TopicExchangeResult res = (TopicExchangeResult)result;
-
-                for(Binding b : res.getBindings())
+            case 0:
+                return Collections.EMPTY_SET;
+            case 1:
+                TopicMatcherResult[] resultQueues = new TopicMatcherResult[1];
+                results.toArray(resultQueues);
+                return ((TopicExchangeResult)resultQueues[0]).processMessage(message, null);
+            default:
+                Collection<AMQQueue> queues = new HashSet<AMQQueue>();
+                for(TopicMatcherResult result : results)
                 {
-                    b.incrementMatches();
+                    TopicExchangeResult res = (TopicExchangeResult)result;
+
+                    for(Binding b : res.getBindings())
+                    {
+                        b.incrementMatches();
+                    }
+
+                    queues = res.processMessage(message, queues);
                 }
-                
-                queues = res.processMessage(message, queues);
-            }
-            return queues;
+                return queues;
         }
 
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java
index 41dc0d7..d8b09a7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicExchangeResult.java
@@ -39,6 +39,7 @@
     private final List<Binding> _bindings = new CopyOnWriteArrayList<Binding>();
     private final Map<AMQQueue, Integer> _unfilteredQueues = new ConcurrentHashMap<AMQQueue, Integer>();
     private final ConcurrentHashMap<AMQQueue, Map<MessageFilter,Integer>> _filteredQueues = new ConcurrentHashMap<AMQQueue, Map<MessageFilter, Integer>>();
+    private volatile ArrayList<AMQQueue> _unfilteredQueueList = new ArrayList<AMQQueue>(0);
 
     public void addUnfilteredQueue(AMQQueue queue)
     {
@@ -46,6 +47,9 @@
         if(instances == null)
         {
             _unfilteredQueues.put(queue, 1);
+            ArrayList<AMQQueue> newList = new ArrayList<AMQQueue>(_unfilteredQueueList);
+            newList.add(queue);
+            _unfilteredQueueList = newList;
         }
         else
         {
@@ -59,6 +63,10 @@
         if(instances == 1)
         {
             _unfilteredQueues.remove(queue);
+            ArrayList<AMQQueue> newList = new ArrayList<AMQQueue>(_unfilteredQueueList);
+            newList.remove(queue);
+            _unfilteredQueueList = newList;
+
         }
         else
         {
@@ -166,7 +174,7 @@
         {
             if(_filteredQueues.isEmpty())
             {
-                return new ArrayList<AMQQueue>(_unfilteredQueues.keySet());
+                return _unfilteredQueueList;
             }
             else
             {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java
index 36076cf..4446536 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/exchange/topic/TopicMatcherDFAState.java
@@ -77,7 +77,7 @@
         }
         if(nextState == null)
         {
-            return Collections.EMPTY_SET;
+            return Collections.EMPTY_LIST;
         }
         // Shortcut if we are at a looping terminal state
         if((nextState == this) && (_nextStateMap.size() == 1) && _nextStateMap.containsKey(TopicWord.ANY_WORD))
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java
index 2dff45c..4db6ee3 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/Bridge.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.federation;
 
 import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQStoreException;
 import org.apache.qpid.server.binding.Binding;
 import org.apache.qpid.server.configuration.BridgeConfig;
 import org.apache.qpid.server.configuration.BridgeConfigType;
@@ -44,32 +45,23 @@
 import org.apache.qpid.server.txn.AutoCommitTransaction;
 import org.apache.qpid.server.txn.ServerTransaction;
 import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageCreditUnit;
-import org.apache.qpid.transport.MessageFlowMode;
-import org.apache.qpid.transport.MessageReject;
-import org.apache.qpid.transport.MessageRejectCode;
-import org.apache.qpid.transport.MessageTransfer;
-import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Session;
-import org.apache.qpid.transport.SessionException;
-import org.apache.qpid.transport.SessionListener;
+import org.apache.qpid.transport.*;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 public class Bridge implements BridgeConfig
 {
+    private static final String DURABLE = "durable";
+    private static final String DYNAMIC = "dynamic";
+    private static final String SRC_IS_QUEUE = "srcIsQueue";
+    private static final String SRC_IS_LOCAL = "srcIsLocal";
+    private static final String SOURCE = "source";
+    private static final String DESTINATION = "destination";
+    private static final String KEY = "key";
+    private static final String TAG = "tag";
+    private static final String EXCLUDES = "excludes";
     private final boolean _durable;
     private final boolean _dynamic;
     private final boolean _queueBridge;
@@ -113,19 +105,36 @@
         _key = key;
         _tag = tag;
         _excludes = excludes;
-        _id = brokerLink.getConfigStore().createId();
+        _id = durable ? brokerLink.getConfigStore().createPersistentId() : brokerLink.getConfigStore().createId();
 
         _transaction = new AutoCommitTransaction(getVirtualHost().getMessageStore());
 
-        if(dynamic)
+        if(durable)
         {
-            if(srcIsLocal)
+            try
+            {
+                brokerLink.getVirtualHost().getDurableConfigurationStore().createBridge(this);
+            }
+            catch (AMQStoreException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        createDelegate();
+    }
+
+    private void createDelegate()
+    {
+        if(_dynamic)
+        {
+            if(_localSource)
             {
                 // TODO
             }
             else
             {
-                if(srcIsQueue)
+                if(_queueBridge)
                 {
                     // TODO
                 }
@@ -137,9 +146,9 @@
         }
         else
         {
-            if(srcIsLocal)
+            if(_localSource)
             {
-                if(srcIsQueue)
+                if(_queueBridge)
                 {
                     _delegate = new StaticQueuePushBridge();
                 }
@@ -150,7 +159,7 @@
             }
             else
             {
-                if(srcIsQueue)
+                if(_queueBridge)
                 {
                     _delegate = new StaticQueuePullBridge();
                 }
@@ -162,6 +171,65 @@
         }
     }
 
+    public Bridge(final BrokerLink brokerLink,
+                  final int bridgeNo,
+                  final UUID id,
+                  final long createTime,
+                  final Map<String, String> arguments)
+    {
+        _link = brokerLink;
+        _bridgeNo = bridgeNo;
+        _id = id;
+        brokerLink.getConfigStore().persistentIdInUse(id);
+        _createTime = createTime;
+
+        _durable = Boolean.valueOf(arguments.get(DURABLE));
+        _dynamic = Boolean.valueOf(arguments.get(DYNAMIC));
+        _queueBridge = Boolean.valueOf(arguments.get(SRC_IS_QUEUE));
+        _localSource = Boolean.valueOf(arguments.get(SRC_IS_LOCAL));
+        _source = arguments.get(SOURCE);
+        _destination = arguments.get(DESTINATION);
+        _key = arguments.get(KEY);
+        _tag = arguments.get(TAG);
+        _excludes = arguments.get(EXCLUDES);
+
+        //TODO.
+        _transaction = new AutoCommitTransaction(getVirtualHost().getMessageStore());
+
+
+        if(_durable)
+        {
+            try
+            {
+                brokerLink.getVirtualHost().getDurableConfigurationStore().createBridge(this);
+            }
+            catch (AMQStoreException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        createDelegate();
+    }
+
+
+    public Map<String,String> getArguments()
+    {
+        Map<String,String> arguments = new HashMap<String, String>();
+
+        arguments.put(DURABLE, String.valueOf(_durable));
+        arguments.put(DYNAMIC, String.valueOf(_dynamic));
+        arguments.put(SRC_IS_QUEUE, String.valueOf(_queueBridge));
+        arguments.put(SRC_IS_LOCAL, String.valueOf(_localSource));
+        arguments.put(SOURCE, _source);
+        arguments.put(DESTINATION, _destination);
+        arguments.put(KEY, _key);
+        arguments.put(TAG, _tag);
+        arguments.put(EXCLUDES, _excludes);
+
+        return Collections.unmodifiableMap(arguments);
+    }
+
     public UUID getId()
     {
         return _id;
@@ -336,6 +404,7 @@
     }
 
 
+
     private interface BridgeImpl
     {
         void setSession(Session session);
@@ -365,7 +434,8 @@
             // TODO - deal with exchange not existing
 
             DeliveryProperties delvProps = null;
-            if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration())
+            if(xfr.getHeader() != null && (delvProps = xfr.getHeader().getDeliveryProperties()) != null && delvProps.hasTtl() &&
+               !delvProps.hasExpiration())
             {
                 delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl());
             }
@@ -377,7 +447,7 @@
             storeMessage.flushToStore();
             MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)_session).getReference());
 
-            ArrayList<? extends BaseQueue> queues = exchange.route(message);
+            List<? extends BaseQueue> queues = exchange.route(message);
 
 
 
@@ -391,7 +461,7 @@
                 {
                     if(xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT)
                     {
-                        RangeSet rejects = new RangeSet();
+                        RangeSet rejects = RangeSetFactory.createRangeSet();
                         rejects.add(xfr.getId());
                         MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable");
                         ssn.invoke(reject);
@@ -428,7 +498,7 @@
         }
 
 
-        private void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues)
+        private void enqueue(final ServerMessage message, final List<? extends BaseQueue> queues)
         {
             _transaction.enqueue(queues,message, new ServerTransaction.Action()
                         {
@@ -456,8 +526,7 @@
                             {
                                 // NO-OP
                             }
-                        });
-
+                        }, 0L);
         }
 
         public void exception(final Session session, final SessionException exception)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java
index f330e2f..a8f75d2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/federation/BrokerLink.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.server.federation;
 
+import org.apache.qpid.AMQStoreException;
 import org.apache.qpid.common.ServerPropertyNames;
 import org.apache.qpid.server.configuration.ConfigStore;
 import org.apache.qpid.server.configuration.ConfiguredObject;
@@ -29,16 +30,19 @@
 import org.apache.qpid.server.configuration.LinkConfigType;
 import org.apache.qpid.server.transport.ServerSession;
 import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.transport.Binary;
-import org.apache.qpid.transport.Connection;
-import org.apache.qpid.transport.ConnectionException;
-import org.apache.qpid.transport.ConnectionListener;
-import org.apache.qpid.transport.Session;
-import org.apache.qpid.transport.SessionDelegate;
-import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.*;
+import org.apache.qpid.util.Strings;
 
-import java.util.Map;
-import java.util.UUID;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import java.io.IOException;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -55,6 +59,14 @@
 
     private static final ScheduledThreadPoolExecutor _threadPool =
             new ScheduledThreadPoolExecutor(CORE_POOL_SIZE);
+    private static final String TRANSPORT   = "transport";
+    private static final String HOST = "host";
+    private static final String PORT = "port";
+    private static final String REMOTE_VHOST = "remoteVhost";
+    private static final String DURABLE = "durable";
+    private static final String AUTH_MECHANISM = "authMechanism";
+    private static final String USERNAME = "username";
+    private static final String PASSWORD = "password";
 
 
     private final String _transport;
@@ -68,7 +80,7 @@
     private final VirtualHost _virtualHost;
     private UUID _id;
     private AtomicBoolean _closing = new AtomicBoolean();
-    private final long _createTime = System.currentTimeMillis();
+    private final long _createTime;
     private Connection _qpidConnection;
     private AtomicReference<Thread> _executor = new AtomicReference<Thread>();
     private AtomicInteger _bridgeId = new AtomicInteger();
@@ -88,8 +100,10 @@
             {
                 doMakeConnection();
             }
-        };;
-    ;
+        };
+
+
+
 
     public static enum State
     {
@@ -205,6 +219,44 @@
         }
     };
 
+    public BrokerLink(final VirtualHost virtualHost, UUID id, long createTime, Map<String, String> arguments)
+    {
+        _virtualHost = virtualHost;
+        _id = id;
+        virtualHost.getConfigStore().persistentIdInUse(id);
+        _createTime = createTime;
+        _transport = arguments.get(TRANSPORT);
+
+        _host = arguments.get(HOST);
+        _port = Integer.parseInt(arguments.get(PORT));
+        _remoteVhost = arguments.get(REMOTE_VHOST);
+        _durable = Boolean.parseBoolean(arguments.get(DURABLE));
+        _authMechanism = arguments.get("authMechanism");
+        _username = arguments.get("username");
+        _password = arguments.get("password");
+
+        if(_durable)
+        {
+            try
+            {
+                _virtualHost.getDurableConfigurationStore().createBrokerLink(this);
+            }
+            catch (AMQStoreException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+
+        _qpidConnection = new Connection();
+        _connectionConfig = new ConnectionConfigAdapter();
+        _qpidConnection.addConnectionListener(this);
+
+
+        makeConnection();
+        
+    }
+
 
     public BrokerLink(final VirtualHost virtualHost,
                       final String transport,
@@ -212,10 +264,13 @@
                       final int port,
                       final String remoteVhost,
                       final boolean durable,
-                      final String authMechanism, final String username, final String password)
+                      final String authMechanism,
+                      final String username,
+                      final String password)
     {
         _virtualHost = virtualHost;
         _transport = transport;
+        _createTime = System.currentTimeMillis();
         _host = host;
         _port = port;
         _remoteVhost = remoteVhost;
@@ -223,15 +278,42 @@
         _authMechanism = authMechanism;
         _username = username;
         _password = password;
-        _id = virtualHost.getConfigStore().createId();
+        _id = durable ? virtualHost.getConfigStore().createPersistentId() : virtualHost.getConfigStore().createId();
+
+        if(durable)
+        {
+            try
+            {
+                _virtualHost.getDurableConfigurationStore().createBrokerLink(this);
+            }
+            catch (AMQStoreException e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
         _qpidConnection = new Connection();
         _connectionConfig = new ConnectionConfigAdapter();
         _qpidConnection.addConnectionListener(this);
 
-
         makeConnection();
     }
 
+    public Map<String,String> getArguments()
+    {
+        Map<String,String> arguments = new HashMap<String, String>();
+        
+        arguments.put(TRANSPORT, _transport);
+        arguments.put(HOST, _host);
+        arguments.put(PORT, String.valueOf(_port));
+        arguments.put(REMOTE_VHOST, _remoteVhost);
+        arguments.put(DURABLE, String.valueOf(_durable));
+        arguments.put(AUTH_MECHANISM, _authMechanism);
+        arguments.put(USERNAME, _username);
+        arguments.put(PASSWORD, _password);
+
+        return Collections.unmodifiableMap(arguments);
+    }
+    
     private final boolean updateState(State expected, State newState)
     {
         return _stateUpdater.compareAndSet(this,expected,newState);
@@ -250,9 +332,50 @@
         {
             try
             {
+                _qpidConnection.setConnectionDelegate(new ClientDelegate(new ConnectionSettings())
+                {
+                    protected SaslClient createSaslClient(List<Object> brokerMechs) throws ConnectionException,
+                                                                                           SaslException
+                    {
+                        Map<String,Object> saslProps = new HashMap<String,Object>();
+
+
+                        CallbackHandler cbh = new CallbackHandler()
+                        {
+                            public void handle(final Callback[] callbacks)
+                                    throws IOException, UnsupportedCallbackException
+                            {
+                                for (int i = 0; i < callbacks.length; i++)
+                                {
+                                    Callback cb = callbacks[i];
+                                    if (cb instanceof NameCallback)
+                                    {
+                                        ((NameCallback)cb).setName(_username);
+                                    }
+                                    else if (cb instanceof PasswordCallback)
+                                    {
+                                        ((PasswordCallback)cb).setPassword(_password.toCharArray());
+                                    }
+                                    else
+                                    {
+                                        throw new UnsupportedCallbackException(cb);
+                                    }
+                            }
+
+                            }
+                        };
+                        final SaslClient sc = Sasl.createSaslClient(new String[] {"PLAIN"}, null,
+                                                                    _conSettings.getSaslProtocol(),
+                                                                    _conSettings.getSaslServerName(),
+                                                                    saslProps, cbh);
+
+                        return sc;
+                }});
+
                 _qpidConnection.connect(_host, _port, _remoteVhost, _username, _password, "ssl".equals(_transport), _authMechanism);
 
                 final Map<String,Object> serverProps = _qpidConnection.getServerProperties();
+
                 _remoteFederationTag = (String) serverProps.get(ServerPropertyNames.FEDERATION_TAG);
                 if(_remoteFederationTag == null)
                 {
@@ -445,6 +568,20 @@
 
     }
 
+    public void createBridge(final UUID id, final long createTime, final Map<String, String> arguments)
+    {
+        if(!_closing.get())
+        {
+            Bridge bridge = new Bridge(this, _bridgeId.incrementAndGet(), id, createTime, arguments);
+            if(_bridges.putIfAbsent(bridge, bridge) == null)
+            {
+
+                addBridge(bridge);
+            }
+        }
+    }
+
+
     private void addBridge(final Bridge bridge)
     {
         getConfigStore().addConfiguredObject(bridge);
@@ -509,4 +646,34 @@
     {
         return _remoteFederationTag;
     }
+
+    public String getState()
+    {
+        return _state.name();
+    }
+
+    public String getLastError()
+    {
+        return _lastErrorMessage;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "BrokerLink{" +
+               " _id=" + _id +
+               ", _transport='" + _transport + '\'' +
+               ", _host='" + _host + '\'' +
+               ", _port=" + _port +
+               ", _remoteVhost='" + _remoteVhost + '\'' +
+               ", _durable=" + _durable +
+               ", _authMechanism='" + _authMechanism + '\'' +
+               ", _username='" + _username + '\'' +
+               ", _password='" + _password + '\'' +
+               ", _virtualHost=" + _virtualHost +
+               ", _createTime=" + _createTime +
+               ", _remoteFederationTag='" + _remoteFederationTag + '\'' +
+               ", _state=" + _state +
+               '}';
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
index cfe5aed..a77ed57 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/flow/AbstractFlowCreditManager.java
@@ -20,6 +20,7 @@
 */
 package org.apache.qpid.server.flow;
 
+import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.Set;
 import java.util.HashSet;
@@ -27,13 +28,16 @@
 public abstract class AbstractFlowCreditManager implements FlowCreditManager
 {
     protected final AtomicBoolean _suspended = new AtomicBoolean(false);
-    private final Set<FlowCreditManagerListener> _listeners = new HashSet<FlowCreditManagerListener>();
+    private final ArrayList<FlowCreditManagerListener> _listeners = new ArrayList<FlowCreditManagerListener>();
 
     public final void addStateListener(FlowCreditManagerListener listener)
     {
         synchronized(_listeners)
         {
-            _listeners.add(listener);
+            if(!_listeners.contains(listener))
+            {
+                _listeners.add(listener);
+            }
         }
     }
 
@@ -49,9 +53,10 @@
     {
         synchronized(_listeners)
         {
-            for(FlowCreditManagerListener listener : _listeners)
+            final int size = _listeners.size();
+            for(int i = 0; i<size; i++)
             {
-                listener.creditStateChanged(!suspended);
+                _listeners.get(i).creditStateChanged(!suspended);
             }
         }
     }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
index 765dee2..8875f21 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/BasicConsumeMethodHandler.java
@@ -52,7 +52,6 @@
         AMQProtocolSession protocolConnection = stateManager.getProtocolSession();
 
         AMQChannel channel = protocolConnection.getChannel(channelId);
-
         VirtualHost vHost = protocolConnection.getVirtualHost();
 
         if (channel == null)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java
index 9133cce..32aa995 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelCloseHandler.java
@@ -65,7 +65,6 @@
         {
             throw body.getConnectionException(AMQConstant.CHANNEL_ERROR, "Trying to close unknown channel");
         }
-
         session.closeChannel(channelId);
         // Client requested closure so we don't wait for ok we send it
         stateManager.getProtocolSession().closeChannelOk(channelId);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java
index 696ca8a..5ccaa49 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ChannelFlowHandler.java
@@ -55,7 +55,6 @@
         {
             throw body.getChannelNotFoundException(channelId);
         }
-
         channel.setSuspended(!body.getActive());
         _logger.debug("Channel.Flow for channel " + channelId + ", active=" + body.getActive());
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java
index f8e4eab..6eaba87 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionCloseMethodHandler.java
@@ -49,7 +49,6 @@
     public void methodReceived(AMQStateManager stateManager, ConnectionCloseBody body, int channelId) throws AMQException
     {
         AMQProtocolSession session = stateManager.getProtocolSession();
-
         if (_logger.isInfoEnabled())
         {
             _logger.info("ConnectionClose received with reply code/reply text " + body.getReplyCode() + "/" +
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java
index ccd4220..21aea15 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ExchangeBoundHandler.java
@@ -65,7 +65,6 @@
     public void methodReceived(AMQStateManager stateManager, ExchangeBoundBody body, int channelId) throws AMQException
     {
         AMQProtocolSession session = stateManager.getProtocolSession();
-        
         VirtualHost virtualHost = session.getVirtualHost();
         QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
         MethodRegistry methodRegistry = session.getMethodRegistry();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
index 0cfed77..693b316 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeclareHandler.java
@@ -85,6 +85,13 @@
         
         //TODO: do we need to check that the queue already exists with exactly the same "configuration"?
 
+        AMQChannel channel = protocolConnection.getChannel(channelId);
+
+        if (channel == null)
+        {
+            throw body.getChannelNotFoundException(channelId);
+        }
+
         synchronized (queueRegistry)
         {
             queue = queueRegistry.getQueue(queueName);
@@ -183,12 +190,6 @@
             }
 
 
-            AMQChannel channel = protocolConnection.getChannel(channelId);
-
-            if (channel == null)
-            {
-                throw body.getChannelNotFoundException(channelId);
-            }
 
             //set this as the default queue on the channel:
             channel.setDefaultQueue(queue);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
index da52268..902e3ad 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueDeleteHandler.java
@@ -64,15 +64,17 @@
         QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
         DurableConfigurationStore store = virtualHost.getDurableConfigurationStore();
 
+
+        AMQChannel channel = protocolConnection.getChannel(channelId);
+
+        if (channel == null)
+        {
+            throw body.getChannelNotFoundException(channelId);
+        }
+
         AMQQueue queue;
         if (body.getQueue() == null)
         {
-            AMQChannel channel = protocolConnection.getChannel(channelId);
-
-            if (channel == null)
-            {
-                throw body.getChannelNotFoundException(channelId);
-            }
 
             //get the default queue on the channel:
             queue = channel.getDefaultQueue();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
index 759eec0..6c3e11b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueuePurgeHandler.java
@@ -63,17 +63,14 @@
         QueueRegistry queueRegistry = virtualHost.getQueueRegistry();
 
         AMQChannel channel = protocolConnection.getChannel(channelId);
-
-
+        if (channel == null)
+        {
+            throw body.getChannelNotFoundException(channelId);
+        }
         AMQQueue queue;
         if(body.getQueue() == null)
         {
 
-           if (channel == null)
-           {
-               throw body.getChannelNotFoundException(channelId);
-           }
-
            //get the default queue on the channel:
            queue = channel.getDefaultQueue();
             
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
index f2119f7..3849c5a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/QueueUnbindHandler.java
@@ -66,14 +66,15 @@
         final AMQQueue queue;
         final AMQShortString routingKey;
 
+
+        AMQChannel channel = session.getChannel(channelId);
+        if (channel == null)
+        {
+            throw body.getChannelNotFoundException(channelId);
+        }
+
         if (body.getQueue() == null)
         {
-            AMQChannel channel = session.getChannel(channelId);
-
-            if (channel == null)
-            {
-                throw body.getChannelNotFoundException(channelId);
-            }
 
             queue = channel.getDefaultQueue();
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java
index 9b35740..885b039 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/ChannelLogSubject.java
@@ -22,6 +22,9 @@
 
 import org.apache.qpid.server.AMQChannel;
 import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.transport.ServerConnection;
+import org.apache.qpid.server.transport.ServerSession;
+
 import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT;
 
 public class ChannelLogSubject extends AbstractLogSubject
@@ -52,5 +55,33 @@
                                session.getVirtualHost().getName(),
                                channel.getChannelId());
     }
-    
+
+    public ChannelLogSubject(ServerSession session)
+    {
+        /**
+         * LOG FORMAT used by the AMQPConnectorActor follows
+         * ChannelLogSubject.CHANNEL_FORMAT :
+         * con:{0}({1}@{2}/{3})/ch:{4}
+         *
+         * Uses a MessageFormat call to insert the required values according to
+         * these indices:
+         *
+         * 0 - Connection ID
+         * 1 - User ID
+         * 2 - IP
+         * 3 - Virtualhost
+         * 4 - Channel ID
+         */
+        if(session.getConnection() instanceof ServerConnection)
+        {
+            ServerConnection connection = (ServerConnection) session.getConnection();
+            setLogStringWithFormat(CHANNEL_FORMAT,
+                                   connection == null ? -1L : connection.getConnectionId(),
+                                   session.getAuthorizedPrincipal() == null ? "?" : session.getAuthorizedPrincipal().getName(),
+                                   (connection == null || connection.getConfig() == null) ? "?" : connection.getConfig().getAddress(),
+                                   session.getVirtualHost().getName(),
+                                   session.getChannel());
+        }
+    }
+
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
index 4fcbaa2..e36e467 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AMQMessage.java
@@ -37,7 +37,7 @@
 /**
  * A deliverable message.
  */
-public class AMQMessage extends AbstractServerMessageImpl
+public class AMQMessage extends AbstractServerMessageImpl<MessageMetaData>
 {
     /** Used for debugging purposes. */
     private static final Logger _log = Logger.getLogger(AMQMessage.class);
@@ -62,9 +62,7 @@
     private Object _sessionIdentifier;
     private static final byte IMMEDIATE_AND_DELIVERED = (byte) (IMMEDIATE | DELIVERED_TO_CONSUMER);
 
-    private final StoredMessage<MessageMetaData> _handle;
-
-    WeakReference<AMQChannel> _channelRef;
+    private WeakReference<AMQChannel> _channelRef;
 
     public AMQMessage(StoredMessage<MessageMetaData> handle)
     {
@@ -75,7 +73,7 @@
     {
         super(handle);
 
-        _handle = handle;
+
         final MessageMetaData metaData = handle.getMetaData();
         _size = metaData.getContentSize();
         final MessagePublishInfo messagePublishInfo = metaData.getMessagePublishInfo();
@@ -97,7 +95,7 @@
 
     public MessageMetaData getMessageMetaData()
     {
-        return _handle.getMetaData();
+        return getStoredMessage().getMetaData();
     }
 
     public ContentHeaderBody getContentHeaderBody() throws AMQException
@@ -107,7 +105,7 @@
 
     public Long getMessageId()
     {
-        return _handle.getMessageNumber();
+        return getStoredMessage().getMessageNumber();
     }
 
     /**
@@ -219,9 +217,9 @@
         return new AMQMessageReference(this);
     }
 
-    public Long getMessageNumber()
+    public long getMessageNumber()
     {
-        return getMessageId();
+        return getStoredMessage().getMessageNumber();
     }
 
 
@@ -248,16 +246,13 @@
 
     public int getContent(ByteBuffer buf, int offset)
     {
-        return _handle.getContent(offset, buf);
+        return getStoredMessage().getContent(offset, buf);
     }
 
-    public StoredMessage<MessageMetaData> getStoredMessage()
+
+    public ByteBuffer getContent(int offset, int size)
     {
-        return _handle;
+        return getStoredMessage().getContent(offset, size);
     }
 
-    public SessionConfig getSessionConfig()
-    {
-        return _channelRef == null ? null : ((SessionConfig) _channelRef.get());
-   }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
index 80c2833..b1d43f0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/AbstractServerMessageImpl.java
@@ -21,19 +21,30 @@
 package org.apache.qpid.server.message;
 
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
 
+import org.apache.qpid.server.store.StorableMessageMetaData;
 import org.apache.qpid.server.store.StoredMessage;
 
-public abstract class AbstractServerMessageImpl implements ServerMessage
+public abstract class AbstractServerMessageImpl<T extends StorableMessageMetaData> implements ServerMessage<T>
 {
-    private final AtomicInteger _referenceCount = new AtomicInteger(0);
-    private final StoredMessage<?> _handle;
 
-    public AbstractServerMessageImpl(StoredMessage<?> handle)
+    private static final AtomicIntegerFieldUpdater<AbstractServerMessageImpl> _refCountUpdater =
+            AtomicIntegerFieldUpdater.newUpdater(AbstractServerMessageImpl.class, "_referenceCount");
+
+    private volatile int _referenceCount = 0;
+    private final StoredMessage<T> _handle;
+
+    public AbstractServerMessageImpl(StoredMessage<T> handle)
     {
         _handle = handle;
     }
 
+    public StoredMessage<T> getStoredMessage()
+    {
+        return _handle;
+    }
+
     public boolean incrementReference()
     {
         return incrementReference(1);
@@ -41,9 +52,9 @@
 
     public boolean incrementReference(int count)
     {
-        if(_referenceCount.addAndGet(count) <= 0)
+        if(_refCountUpdater.addAndGet(this, count) <= 0)
         {
-            _referenceCount.addAndGet(-count);
+            _refCountUpdater.addAndGet(this, -count);
             return false;
         }
         else
@@ -62,7 +73,7 @@
      */
     public void decrementReference()
     {
-        int count = _referenceCount.decrementAndGet();
+        int count = _refCountUpdater.decrementAndGet(this);
 
         // note that the operation of decrementing the reference count and then removing the message does not
         // have to be atomic since the ref count starts at 1 and the exchange itself decrements that after
@@ -73,7 +84,7 @@
             // set the reference count way below 0 so that we can detect that the message has been deleted
             // this is to guard against the message being spontaneously recreated (from the mgmt console)
             // by copying from other queues at the same time as it is being removed.
-            _referenceCount.set(Integer.MIN_VALUE/2);
+            _refCountUpdater.set(this,Integer.MIN_VALUE/2);
 
             // must check if the handle is null since there may be cases where we decide to throw away a message
             // and the handle has not yet been constructed
@@ -99,6 +110,6 @@
 
     protected int getReferenceCount()
     {
-        return _referenceCount.get();
+        return _referenceCount;
     }
 }
\ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java
index c32f80f..7be91ad 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/EnqueableMessage.java
@@ -20,8 +20,11 @@
 */
 package org.apache.qpid.server.message;
 
+import org.apache.qpid.server.store.StoredMessage;
+
 public interface EnqueableMessage
 {
-    Long getMessageNumber();
+    long getMessageNumber();
     boolean isPersistent();
+    StoredMessage getStoredMessage();
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java
index 1b3fdb1..79d5574 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/InboundMessage.java
@@ -22,10 +22,12 @@
 
 
 import org.apache.qpid.server.queue.Filterable;
+import org.apache.qpid.framing.AMQShortString;
 
 public interface InboundMessage extends Filterable
 {
     String getRoutingKey();
+    AMQShortString getRoutingKeyShortString();
 
     AMQMessageHeader getMessageHeader();
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java
index 08a09c4..44741f5 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageContentSource.java
@@ -26,6 +26,7 @@
 public interface MessageContentSource
 {
     public int getContent(ByteBuffer buf, int offset);
+    public ByteBuffer getContent(int offset, int size);
 
     long getSize();
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java
index 5992e42..9bfa0bb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData.java
@@ -29,8 +29,8 @@
 import org.apache.qpid.server.store.StorableMessageMetaData;
 import org.apache.qpid.server.store.MessageMetaDataType;
 import org.apache.qpid.AMQException;
-import org.apache.qpid.server.util.ByteBufferInputStream;
 import org.apache.qpid.server.util.ByteBufferOutputStream;
+import org.apache.qpid.util.ByteBufferInputStream;
 
 import java.io.*;
 import java.nio.ByteBuffer;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java
index f9863f4..17ebb6e 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_0_10.java
@@ -30,9 +30,12 @@
 import org.apache.qpid.transport.Struct;
 import org.apache.qpid.transport.codec.BBEncoder;
 import org.apache.qpid.transport.codec.BBDecoder;
+import org.apache.qpid.framing.AMQShortString;
 
 import java.nio.ByteBuffer;
 import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.List;
 
 public class MessageMetaData_0_10 implements StorableMessageMetaData, InboundMessage
 {
@@ -42,7 +45,6 @@
     private MessageTransferHeader _messageHeader;
     private long _arrivalTime;
     private int _bodySize;
-    private volatile SoftReference<ByteBuffer> _body;
 
     private static final int ENCODER_SIZE = 1 << 10;
 
@@ -53,21 +55,16 @@
 
     public MessageMetaData_0_10(MessageTransfer xfr)
     {
-        this(xfr.getHeader(), xfr.getBodySize(), xfr.getBody(), System.currentTimeMillis());
+        this(xfr.getHeader(), xfr.getBodySize(), System.currentTimeMillis());
     }
 
     private MessageMetaData_0_10(Header header, int bodySize, long arrivalTime)
     {
-        this(header, bodySize, null, arrivalTime);
-    }
-
-    private MessageMetaData_0_10(Header header, int bodySize, ByteBuffer xfrBody, long arrivalTime)
-    {
         _header = header;
         if(_header != null)
         {
-            _deliveryProps = _header.get(DeliveryProperties.class);
-            _messageProps = _header.get(MessageProperties.class);
+            _deliveryProps = _header.getDeliveryProperties();
+            _messageProps = _header.getMessageProperties();
         }
         else
         {
@@ -78,21 +75,6 @@
         _arrivalTime = arrivalTime;
         _bodySize = bodySize;
 
-
-
-        if(xfrBody == null)
-        {
-            _body = null;
-        }
-        else
-        {
-            ByteBuffer body = ByteBuffer.allocate(_bodySize);
-            body.put(xfrBody);
-            body.flip();
-            _body = new SoftReference<ByteBuffer>(body);
-        }
-
-
     }
 
 
@@ -122,16 +104,39 @@
 
         encoder.writeInt64(_arrivalTime);
         encoder.writeInt32(_bodySize);
-        Struct[] headers = _header == null ? new Struct[0] : _header.getStructs();
-        encoder.writeInt32(headers.length);
-
-
-        for(Struct header : headers)
+        int headersLength = 0;
+        if(_header.getDeliveryProperties() != null)
         {
-            encoder.writeStruct32(header);
-
+            headersLength++;
+        }
+        if(_header.getMessageProperties() != null)
+        {
+            headersLength++;
+        }
+        if(_header.getNonStandardProperties() != null)
+        {
+            headersLength += _header.getNonStandardProperties().size();
         }
 
+        encoder.writeInt32(headersLength);
+
+        if(_header.getDeliveryProperties() != null)
+        {
+            encoder.writeStruct32(_header.getDeliveryProperties());
+        }
+        if(_header.getMessageProperties() != null)
+        {
+            encoder.writeStruct32(_header.getMessageProperties());
+        }
+        if(_header.getNonStandardProperties() != null)
+        {
+
+            for(Struct header : _header.getNonStandardProperties())
+            {
+                encoder.writeStruct32(header);
+            }
+
+        }
         ByteBuffer buf = encoder.buffer();
         return buf;
     }
@@ -173,6 +178,11 @@
         return _deliveryProps == null ? null : _deliveryProps.getRoutingKey();
     }
 
+    public AMQShortString getRoutingKeyShortString()
+    {
+        return AMQShortString.valueOf(getRoutingKey());
+    }
+
     public AMQMessageHeader getMessageHeader()
     {
         return _messageHeader;
@@ -210,17 +220,6 @@
         return _header;
     }
 
-    public ByteBuffer getBody()
-    {
-        ByteBuffer body = _body == null ? null : _body.get();
-        return body;
-    }
-
-    public void setBody(ByteBuffer body)
-    {
-        _body = new SoftReference<ByteBuffer>(body);
-    }
-
     private static class MetaDataFactory implements MessageMetaDataType.Factory<MessageMetaData_0_10>
     {
         public MessageMetaData_0_10 createMetaData(ByteBuffer buf)
@@ -232,14 +231,32 @@
             int bodySize = decoder.readInt32();
             int headerCount = decoder.readInt32();
 
-            Struct[] headers = new Struct[headerCount];
+            DeliveryProperties deliveryProperties = null;
+            MessageProperties messageProperties = null;
+            List<Struct> otherProps = null;
 
             for(int i = 0 ; i < headerCount; i++)
             {
-                headers[i] = decoder.readStruct32();
-            }
+                Struct struct = decoder.readStruct32();
+                if(struct instanceof DeliveryProperties && deliveryProperties == null)
+                {
+                    deliveryProperties = (DeliveryProperties) struct;
+                }
+                else if(struct instanceof MessageProperties && messageProperties == null)
+                {
+                    messageProperties = (MessageProperties) struct;
+                }
+                else
+                {
+                    if(otherProps == null)
+                    {
+                        otherProps = new ArrayList<Struct>();
 
-            Header header = new Header(headers);
+                    }
+                    otherProps.add(struct);
+                }
+            }
+            Header header = new Header(deliveryProperties,messageProperties,otherProps);
 
             return new MessageMetaData_0_10(header, bodySize, arrivalTime);
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java
index d160d91..9cb5904 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageMetaData_1_0.java
@@ -20,25 +20,30 @@
 */
 package org.apache.qpid.server.message;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import org.apache.qpid.amqp_1_0.codec.ValueHandler;
 import org.apache.qpid.amqp_1_0.messaging.SectionDecoder;
 import org.apache.qpid.amqp_1_0.type.AmqpErrorException;
-import org.apache.qpid.amqp_1_0.type.Binary;
 import org.apache.qpid.amqp_1_0.type.Section;
 import org.apache.qpid.amqp_1_0.type.Symbol;
-import org.apache.qpid.amqp_1_0.type.UnsignedInteger;
 import org.apache.qpid.amqp_1_0.type.codec.AMQPDescribedTypeRegistry;
-import org.apache.qpid.amqp_1_0.type.messaging.*;
-
-
+import org.apache.qpid.amqp_1_0.type.messaging.AmqpSequence;
+import org.apache.qpid.amqp_1_0.type.messaging.AmqpValue;
+import org.apache.qpid.amqp_1_0.type.messaging.ApplicationProperties;
+import org.apache.qpid.amqp_1_0.type.messaging.Data;
+import org.apache.qpid.amqp_1_0.type.messaging.DeliveryAnnotations;
+import org.apache.qpid.amqp_1_0.type.messaging.Footer;
+import org.apache.qpid.amqp_1_0.type.messaging.Header;
+import org.apache.qpid.amqp_1_0.type.messaging.MessageAnnotations;
 import org.apache.qpid.amqp_1_0.type.messaging.Properties;
-import org.apache.qpid.configuration.Validator;
 import org.apache.qpid.server.store.MessageMetaDataType;
 import org.apache.qpid.server.store.StorableMessageMetaData;
 
-import java.nio.ByteBuffer;
-import java.util.*;
-
 public class MessageMetaData_1_0 implements StorableMessageMetaData
 {
     // TODO move to somewhere more useful
@@ -312,6 +317,18 @@
         return buf.limit();
     }
 
+    public int getContentSize()
+    {
+        ByteBuffer buf = _encoded;
+
+        if(buf == null)
+        {
+            buf = encodeAsBuffer();
+            _encoded = buf;
+        }
+        return buf.remaining();
+    }
+
     public boolean isPersistent()
     {
         return _header != null && Boolean.TRUE.equals(_header.getDurable());
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java
index 1a230a2..c4d2a19 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/MessageTransferMessage.java
@@ -24,32 +24,35 @@
 import org.apache.qpid.server.configuration.SessionConfig;
 import org.apache.qpid.server.store.StoredMessage;
 import org.apache.qpid.server.transport.ServerSession;
+import org.apache.qpid.framing.AMQShortString;
 
 import java.nio.ByteBuffer;
-import java.lang.ref.WeakReference;
 
 
-public class MessageTransferMessage extends AbstractServerMessageImpl implements InboundMessage
+public class MessageTransferMessage extends AbstractServerMessageImpl<MessageMetaData_0_10> implements InboundMessage
 {
-    private StoredMessage<MessageMetaData_0_10> _storeMessage;
-    private WeakReference<Session> _sessionRef;
 
-    public MessageTransferMessage(StoredMessage<MessageMetaData_0_10> storeMessage, WeakReference<Session> sessionRef)
+    private Object _connectionRef;
+
+    public MessageTransferMessage(StoredMessage<MessageMetaData_0_10> storeMessage, Object connectionRef)
     {
         super(storeMessage);
-        _storeMessage = storeMessage;
-        _sessionRef = sessionRef;
+        _connectionRef = connectionRef;
     }
 
     private MessageMetaData_0_10 getMetaData()
     {
-        return _storeMessage.getMetaData();
+        return getStoredMessage().getMetaData();
     }
 
     public String getRoutingKey()
     {
         return getMetaData().getRoutingKey();
+    }
 
+    public AMQShortString getRoutingKeyShortString()
+    {
+        return AMQShortString.valueOf(getRoutingKey());
     }
 
     public AMQMessageHeader getMessageHeader()
@@ -91,9 +94,9 @@
         return new TransferMessageReference(this);
     }
 
-    public Long getMessageNumber()
+    public long getMessageNumber()
     {
-        return _storeMessage.getMessageNumber();
+        return getStoredMessage().getMessageNumber();
     }
 
     public long getArrivalTime()
@@ -103,7 +106,13 @@
 
     public int getContent(ByteBuffer buf, int offset)
     {
-        return _storeMessage.getContent(offset, buf);
+        return getStoredMessage().getContent(offset, buf);
+    }
+
+
+    public ByteBuffer getContent(int offset, int size)
+    {
+        return getStoredMessage().getContent(offset,size);
     }
 
     public Header getHeader()
@@ -113,32 +122,13 @@
 
     public ByteBuffer getBody()
     {
-        ByteBuffer body = getMetaData().getBody();
-        if(body == null && getSize() != 0l)
-        {
-            final int size = (int) getSize();
-            int pos = 0;
-            body = ByteBuffer.allocate(size);
 
-            while(pos < size)
-            {
-                pos += getContent(body, pos);
-            }
-
-            body.flip();
-
-            getMetaData().setBody(body.duplicate());
-        }
-        return body;
+        return  getContent(0, (int)getSize());
     }
 
-    public Session getSession()
+    public Object getConnectionReference()
     {
-        return _sessionRef == null ? null : _sessionRef.get();
+        return _connectionRef;
     }
 
-    public SessionConfig getSessionConfig()
-    {
-        return _sessionRef == null ? null : (ServerSession) _sessionRef.get();
-    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java
index e3cc987..d354d3b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/message/ServerMessage.java
@@ -22,14 +22,17 @@
 
 import java.nio.ByteBuffer;
 
-import org.apache.qpid.server.configuration.SessionConfig;
+import org.apache.qpid.server.store.StorableMessageMetaData;
+import org.apache.qpid.server.store.StoredMessage;
 
-public interface ServerMessage<T extends ServerMessage> extends EnqueableMessage, MessageContentSource
+public interface ServerMessage<T extends StorableMessageMetaData> extends EnqueableMessage, MessageContentSource
 {
     String getRoutingKey();
 
     AMQMessageHeader getMessageHeader();
 
+    public StoredMessage<T> getStoredMessage();
+
     boolean isPersistent();
 
     long getSize();
@@ -38,13 +41,14 @@
 
     long getExpiration();
 
-    MessageReference<T> newReference();
+    MessageReference newReference();
 
-    Long getMessageNumber();
+    long getMessageNumber();
 
     long getArrivalTime();
 
     public int getContent(ByteBuffer buf, int offset);
 
-    SessionConfig getSessionConfig();
+    public ByteBuffer getContent(int offset, int size);
+
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java
index aded3f3..483bca8 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/HeaderPropertiesConverter.java
@@ -40,8 +40,8 @@
         BasicContentHeaderProperties props = new BasicContentHeaderProperties();
 
         Header header = messageTransferMessage.getHeader();
-        DeliveryProperties deliveryProps = header.get(DeliveryProperties.class);
-        MessageProperties messageProps = header.get(MessageProperties.class);
+        DeliveryProperties deliveryProps = header.getDeliveryProperties();
+        MessageProperties messageProps = header.getMessageProperties();
 
         if(deliveryProps != null)
         {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
index 3970e5a..efd904f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_8/ProtocolOutputConverterImpl.java
@@ -1,420 +1,420 @@
-/*

- *

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- *

- *   http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- *

- */

-

-/*

- * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.

- * Supported AMQP versions:

- *   8-0

- */

-package org.apache.qpid.server.output.amqp0_8;

-

-import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;

-import org.apache.qpid.server.protocol.AMQProtocolSession;

-import org.apache.qpid.server.message.AMQMessage;

-import org.apache.qpid.server.queue.QueueEntry;

-import org.apache.qpid.server.output.ProtocolOutputConverter;

-import org.apache.qpid.server.output.HeaderPropertiesConverter;

-import org.apache.qpid.server.message.MessageContentSource;

-import org.apache.qpid.server.message.MessageTransferMessage;

-import org.apache.qpid.framing.*;

-import org.apache.qpid.framing.abstraction.MessagePublishInfo;

-import org.apache.qpid.AMQException;

-import org.apache.qpid.transport.DeliveryProperties;

-

-import java.io.DataOutputStream;

-import java.io.IOException;

-

-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter

-{

-

-    private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);

-

-    public static Factory getInstanceFactory()

-    {

-        return new Factory()

-        {

-

-            public ProtocolOutputConverter newInstance(AMQProtocolSession session)

-            {

-                return new ProtocolOutputConverterImpl(session);

-            }

-        };

-    }

-

-

-    private final AMQProtocolSession _protocolSession;

-

-    private ProtocolOutputConverterImpl(AMQProtocolSession session)

-    {

-        _protocolSession = session;

-    }

-

-

-    public AMQProtocolSession getProtocolSession()

-    {

-        return _protocolSession;

-    }

-

-    public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)

-            throws AMQException

-    {

-        AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);

-        writeMessageDelivery(entry, channelId, deliverBody);

-    }

-

-

-    private ContentHeaderBody getContentHeaderBody(QueueEntry entry)

-            throws AMQException

-    {

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            return ((AMQMessage)entry.getMessage()).getContentHeaderBody();

-        }

-        else

-        {

-            final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);

-            ContentHeaderBody chb = new ContentHeaderBody(props, org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl.CLASS_ID);

-            chb.bodySize = message.getSize();

-            return chb;

-        }

-    }

-

-

-    private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)

-            throws AMQException

-    {

-        writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);

-    }

-

-    private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)

-            throws AMQException

-    {

-

-

-        int bodySize = (int) message.getSize();

-

-        if(bodySize == 0)

-        {

-            SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,

-                                                                             contentHeaderBody);

-

-            writeFrame(compositeBlock);

-        }

-        else

-        {

-            int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();

-

-

-            int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;

-

-            int writtenSize = capacity;

-

-            AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);

-

-            CompositeAMQBodyBlock

-                    compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);

-            writeFrame(compositeBlock);

-

-            while(writtenSize < bodySize)

-            {

-                capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;

-                MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);

-                writtenSize += capacity;

-

-                writeFrame(new AMQFrame(channelId, body));

-            }

-        }

-    }

-

-    private class MessageContentSourceBody implements AMQBody

-    {

-        public static final byte TYPE = 3;

-        private int _length;

-        private MessageContentSource _message;

-        private int _offset;

-

-        public MessageContentSourceBody(MessageContentSource message, int offset, int length)

-        {

-            _message = message;

-            _offset = offset;

-            _length = length;

-        }

-

-        public byte getFrameType()

-        {

-            return TYPE;

-        }

-

-        public int getSize()

-        {

-            return _length;

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            byte[] data = new byte[_length];

-

-            _message.getContent(java.nio.ByteBuffer.wrap(data), _offset);

-

-            buffer.write(data);

-        }

-

-        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException

-        {

-            throw new UnsupportedOperationException();

-        }

-    }

-

-    private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)

-    {

-

-        AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,

-                                                                      contentHeaderBody);

-        return contentHeader;

-    }

-

-

-    public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException

-    {

-        AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);

-        writeMessageDelivery(entry, channelId, deliver);

-    }

-

-

-    private AMQBody createEncodedDeliverBody(QueueEntry entry,

-                                              final long deliveryTag,

-                                              final AMQShortString consumerTag)

-            throws AMQException

-    {

-

-        final AMQShortString exchangeName;

-        final AMQShortString routingKey;

-

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            final AMQMessage message = (AMQMessage) entry.getMessage();

-            final MessagePublishInfo pb = message.getMessagePublishInfo();

-            exchangeName = pb.getExchange();

-            routingKey = pb.getRoutingKey();

-        }

-        else

-        {

-            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);

-            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());

-            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());

-        }

-

-        final boolean isRedelivered = entry.isRedelivered();

-

-        final AMQBody returnBlock = new AMQBody()

-        {

-

-            public AMQBody _underlyingBody;

-

-            public AMQBody createAMQBody()

-            {

-                return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,

-                                                              deliveryTag,

-                                                              isRedelivered,

-                                                              exchangeName,

-                                                              routingKey);

-

-

-

-

-

-            }

-

-            public byte getFrameType()

-            {

-                return AMQMethodBody.TYPE;

-            }

-

-            public int getSize()

-            {

-                if(_underlyingBody == null)

-                {

-                    _underlyingBody = createAMQBody();

-                }

-                return _underlyingBody.getSize();

-            }

-

-            public void writePayload(DataOutputStream buffer) throws IOException

-            {

-                if(_underlyingBody == null)

-                {

-                    _underlyingBody = createAMQBody();

-                }

-                _underlyingBody.writePayload(buffer);

-            }

-

-            public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)

-                throws AMQException

-            {

-                throw new AMQException("This block should never be dispatched!");

-            }

-        };

-        return returnBlock;

-    }

-

-    private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)

-            throws AMQException

-    {

-        final AMQShortString exchangeName;

-        final AMQShortString routingKey;

-

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            final AMQMessage message = (AMQMessage) entry.getMessage();

-            final MessagePublishInfo pb = message.getMessagePublishInfo();

-            exchangeName = pb.getExchange();

-            routingKey = pb.getRoutingKey();

-        }

-        else

-        {

-            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);

-            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());

-            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());

-        }

-

-        final boolean isRedelivered = entry.isRedelivered();

-

-        BasicGetOkBody getOkBody =

-                METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,

-                                                    isRedelivered,

-                                                    exchangeName,

-                                                    routingKey,

-                                                    queueSize);

-

-        return getOkBody;

-    }

-

-    public byte getProtocolMinorVersion()

-    {

-        return getProtocolSession().getProtocolMinorVersion();

-    }

-

-    public byte getProtocolMajorVersion()

-    {

-        return getProtocolSession().getProtocolMajorVersion();

-    }

-

-    private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,

-                                             int replyCode,

-                                             AMQShortString replyText) throws AMQException

-    {

-

-        BasicReturnBody basicReturnBody =

-                METHOD_REGISTRY.createBasicReturnBody(replyCode,

-                        replyText,

-                        messagePublishInfo.getExchange(),

-                        messagePublishInfo.getRoutingKey());

-

-

-        return basicReturnBody;

-    }

-

-    public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)

-            throws AMQException

-    {

-

-        AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);

-

-        writeMessageDelivery(message, header, channelId, returnFrame);

-    }

-

-

-    public void writeFrame(AMQDataBlock block)

-    {

-        getProtocolSession().writeFrame(block);

-    }

-

-

-    public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)

-    {

-

-        BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);

-        writeFrame(basicCancelOkBody.generateFrame(channelId));

-

-    }

-

-

-    public static final class CompositeAMQBodyBlock extends AMQDataBlock

-    {

-        public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();

-

-        private final AMQBody _methodBody;

-        private final AMQBody _headerBody;

-        private final AMQBody _contentBody;

-        private final int _channel;

-

-

-        public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)

-        {

-            _channel = channel;

-            _methodBody = methodBody;

-            _headerBody = headerBody;

-            _contentBody = contentBody;

-

-        }

-

-        public long getSize()

-        {

-            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);

-        }

-    }

-

-    public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock

-    {

-        public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();

-

-        private final AMQBody _methodBody;

-        private final AMQBody _headerBody;

-        private final int _channel;

-

-

-        public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)

-        {

-            _channel = channel;

-            _methodBody = methodBody;

-            _headerBody = headerBody;

-

-        }

-

-        public long getSize()

-        {

-            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);

-        }

-    }

-}

+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+/*
+ * This file is auto-generated by Qpid Gentools v.0.1 - do not modify.
+ * Supported AMQP versions:
+ *   8-0
+ */
+package org.apache.qpid.server.output.amqp0_8;
+
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
+
+import java.io.DataOutput;
+import java.io.IOException;
+
+public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
+{
+
+    private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v8_0);
+
+    public static Factory getInstanceFactory()
+    {
+        return new Factory()
+        {
+
+            public ProtocolOutputConverter newInstance(AMQProtocolSession session)
+            {
+                return new ProtocolOutputConverterImpl(session);
+            }
+        };
+    }
+
+
+    private final AMQProtocolSession _protocolSession;
+
+    private ProtocolOutputConverterImpl(AMQProtocolSession session)
+    {
+        _protocolSession = session;
+    }
+
+
+    public AMQProtocolSession getProtocolSession()
+    {
+        return _protocolSession;
+    }
+
+    public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
+            throws AMQException
+    {
+        AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
+        writeMessageDelivery(entry, channelId, deliverBody);
+    }
+
+
+    private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+            throws AMQException
+    {
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
+        }
+        else
+        {
+            final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+            ContentHeaderBody chb = new ContentHeaderBody(props, org.apache.qpid.framing.amqp_8_0.BasicGetBodyImpl.CLASS_ID);
+            chb.bodySize = message.getSize();
+            return chb;
+        }
+    }
+
+
+    private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)
+            throws AMQException
+    {
+        writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);
+    }
+
+    private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)
+            throws AMQException
+    {
+
+
+        int bodySize = (int) message.getSize();
+
+        if(bodySize == 0)
+        {
+            SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
+                                                                             contentHeaderBody);
+
+            writeFrame(compositeBlock);
+        }
+        else
+        {
+            int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+
+            int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+
+            int writtenSize = capacity;
+
+            AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);
+
+            CompositeAMQBodyBlock
+                    compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+            writeFrame(compositeBlock);
+
+            while(writtenSize < bodySize)
+            {
+                capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
+                MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);
+                writtenSize += capacity;
+
+                writeFrame(new AMQFrame(channelId, body));
+            }
+        }
+    }
+
+    private class MessageContentSourceBody implements AMQBody
+    {
+        public static final byte TYPE = 3;
+        private int _length;
+        private MessageContentSource _message;
+        private int _offset;
+
+        public MessageContentSourceBody(MessageContentSource message, int offset, int length)
+        {
+            _message = message;
+            _offset = offset;
+            _length = length;
+        }
+
+        public byte getFrameType()
+        {
+            return TYPE;
+        }
+
+        public int getSize()
+        {
+            return _length;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            byte[] data = new byte[_length];
+
+            _message.getContent(java.nio.ByteBuffer.wrap(data), _offset);
+
+            buffer.write(data);
+        }
+
+        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
+        {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
+    {
+
+        AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+                                                                      contentHeaderBody);
+        return contentHeader;
+    }
+
+
+    public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
+    {
+        AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
+        writeMessageDelivery(entry, channelId, deliver);
+    }
+
+
+    private AMQBody createEncodedDeliverBody(QueueEntry entry,
+                                              final long deliveryTag,
+                                              final AMQShortString consumerTag)
+            throws AMQException
+    {
+
+        final AMQShortString exchangeName;
+        final AMQShortString routingKey;
+
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            final AMQMessage message = (AMQMessage) entry.getMessage();
+            final MessagePublishInfo pb = message.getMessagePublishInfo();
+            exchangeName = pb.getExchange();
+            routingKey = pb.getRoutingKey();
+        }
+        else
+        {
+            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            DeliveryProperties delvProps = message.getHeader().getDeliveryProperties();
+            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+        }
+
+        final boolean isRedelivered = entry.isRedelivered();
+
+        final AMQBody returnBlock = new AMQBody()
+        {
+
+            public AMQBody _underlyingBody;
+
+            public AMQBody createAMQBody()
+            {
+                return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
+                                                              deliveryTag,
+                                                              isRedelivered,
+                                                              exchangeName,
+                                                              routingKey);
+
+
+
+
+
+            }
+
+            public byte getFrameType()
+            {
+                return AMQMethodBody.TYPE;
+            }
+
+            public int getSize()
+            {
+                if(_underlyingBody == null)
+                {
+                    _underlyingBody = createAMQBody();
+                }
+                return _underlyingBody.getSize();
+            }
+
+            public void writePayload(DataOutput buffer) throws IOException
+            {
+                if(_underlyingBody == null)
+                {
+                    _underlyingBody = createAMQBody();
+                }
+                _underlyingBody.writePayload(buffer);
+            }
+
+            public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
+                throws AMQException
+            {
+                throw new AMQException("This block should never be dispatched!");
+            }
+        };
+        return returnBlock;
+    }
+
+    private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
+            throws AMQException
+    {
+        final AMQShortString exchangeName;
+        final AMQShortString routingKey;
+
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            final AMQMessage message = (AMQMessage) entry.getMessage();
+            final MessagePublishInfo pb = message.getMessagePublishInfo();
+            exchangeName = pb.getExchange();
+            routingKey = pb.getRoutingKey();
+        }
+        else
+        {
+            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            DeliveryProperties delvProps = message.getHeader().getDeliveryProperties();
+            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+        }
+
+        final boolean isRedelivered = entry.isRedelivered();
+
+        BasicGetOkBody getOkBody =
+                METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+                                                    isRedelivered,
+                                                    exchangeName,
+                                                    routingKey,
+                                                    queueSize);
+
+        return getOkBody;
+    }
+
+    public byte getProtocolMinorVersion()
+    {
+        return getProtocolSession().getProtocolMinorVersion();
+    }
+
+    public byte getProtocolMajorVersion()
+    {
+        return getProtocolSession().getProtocolMajorVersion();
+    }
+
+    private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
+                                             int replyCode,
+                                             AMQShortString replyText) throws AMQException
+    {
+
+        BasicReturnBody basicReturnBody =
+                METHOD_REGISTRY.createBasicReturnBody(replyCode,
+                        replyText,
+                        messagePublishInfo.getExchange(),
+                        messagePublishInfo.getRoutingKey());
+
+
+        return basicReturnBody;
+    }
+
+    public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
+            throws AMQException
+    {
+
+        AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
+
+        writeMessageDelivery(message, header, channelId, returnFrame);
+    }
+
+
+    public void writeFrame(AMQDataBlock block)
+    {
+        getProtocolSession().writeFrame(block);
+    }
+
+
+    public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+    {
+
+        BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
+        writeFrame(basicCancelOkBody.generateFrame(channelId));
+
+    }
+
+
+    public static final class CompositeAMQBodyBlock extends AMQDataBlock
+    {
+        public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
+
+        private final AMQBody _methodBody;
+        private final AMQBody _headerBody;
+        private final AMQBody _contentBody;
+        private final int _channel;
+
+
+        public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
+        {
+            _channel = channel;
+            _methodBody = methodBody;
+            _headerBody = headerBody;
+            _contentBody = contentBody;
+
+        }
+
+        public long getSize()
+        {
+            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
+        }
+    }
+
+    public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
+    {
+        public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
+
+        private final AMQBody _methodBody;
+        private final AMQBody _headerBody;
+        private final int _channel;
+
+
+        public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
+        {
+            _channel = channel;
+            _methodBody = methodBody;
+            _headerBody = headerBody;
+
+        }
+
+        public long getSize()
+        {
+            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
+        }
+    }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
index aef3483..010afcb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9/ProtocolOutputConverterImpl.java
@@ -1,419 +1,418 @@
-package org.apache.qpid.server.output.amqp0_9;

-/*

- *

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- *

- *   http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- *

- */

-

-import org.apache.qpid.server.output.ProtocolOutputConverter;

-import org.apache.qpid.server.output.HeaderPropertiesConverter;

-import org.apache.qpid.server.protocol.AMQProtocolSession;

-import org.apache.qpid.server.message.AMQMessage;

-import org.apache.qpid.server.queue.QueueEntry;

-import org.apache.qpid.server.message.MessageContentSource;

-import org.apache.qpid.server.message.MessageTransferMessage;

-import org.apache.qpid.framing.*;

-import org.apache.qpid.framing.amqp_0_9.BasicGetBodyImpl;

-import org.apache.qpid.framing.abstraction.MessagePublishInfo;

-import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;

-import org.apache.qpid.AMQException;

-import org.apache.qpid.transport.DeliveryProperties;

-import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;

-

-import java.io.DataOutputStream;

-import java.io.IOException;

-import java.nio.ByteBuffer;

-

-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter

-{

-    private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);

-

-

-    public static Factory getInstanceFactory()

-    {

-        return new Factory()

-        {

-

-            public ProtocolOutputConverter newInstance(AMQProtocolSession session)

-            {

-                return new ProtocolOutputConverterImpl(session);

-            }

-        };

-    }

-

-    private final AMQProtocolSession _protocolSession;

-

-    private ProtocolOutputConverterImpl(AMQProtocolSession session)

-    {

-        _protocolSession = session;

-    }

-

-

-    public AMQProtocolSession getProtocolSession()

-    {

-        return _protocolSession;

-    }

-

-    public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)

-            throws AMQException

-    {

-        AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);

-        writeMessageDelivery(entry, channelId, deliverBody);

-    }

-

-

-    private ContentHeaderBody getContentHeaderBody(QueueEntry entry)

-            throws AMQException

-    {

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            return ((AMQMessage)entry.getMessage()).getContentHeaderBody();

-        }

-        else

-        {

-            final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);

-            ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);

-            chb.bodySize = message.getSize();

-            return chb;

-        }

-    }

-

-

-    private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)

-            throws AMQException

-    {

-        writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);

-    }

-

-    private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)

-            throws AMQException

-    {

-

-

-        int bodySize = (int) message.getSize();

-

-        if(bodySize == 0)

-        {

-            SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,

-                                                                             contentHeaderBody);

-

-            writeFrame(compositeBlock);

-        }

-        else

-        {

-            int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();

-

-

-            int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;

-

-            int writtenSize = capacity;

-

-            AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);

-

-

-            CompositeAMQBodyBlock

-                    compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);

-            writeFrame(compositeBlock);

-

-            while(writtenSize < bodySize)

-            {

-                capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;

-                MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);

-                writtenSize += capacity;

-

-                writeFrame(new AMQFrame(channelId, body));

-            }

-        }

-    }

-

-    private class MessageContentSourceBody implements AMQBody

-    {

-        public static final byte TYPE = 3;

-        private int _length;

-        private MessageContentSource _message;

-        private int _offset;

-

-        public MessageContentSourceBody(MessageContentSource message, int offset, int length)

-        {

-            _message = message;

-            _offset = offset;

-            _length = length;

-        }

-

-        public byte getFrameType()

-        {

-            return TYPE;

-        }

-

-        public int getSize()

-        {

-            return _length;

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            byte[] data = new byte[_length];

-

-            _message.getContent(ByteBuffer.wrap(data), _offset);

-

-            buffer.write(data);

-        }

-

-        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException

-        {

-            throw new UnsupportedOperationException();

-        }

-    }

-

-

-    private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)

-    {

-

-        AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,

-                                                                      contentHeaderBody);

-        return contentHeader;

-    }

-

-

-    public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException

-    {

-        AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);

-        writeMessageDelivery(entry, channelId, deliver);

-    }

-

-

-    private AMQBody createEncodedDeliverBody(QueueEntry entry,

-                                              final long deliveryTag,

-                                              final AMQShortString consumerTag)

-            throws AMQException

-    {

-

-        final AMQShortString exchangeName;

-        final AMQShortString routingKey;

-

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            final AMQMessage message = (AMQMessage) entry.getMessage();

-            final MessagePublishInfo pb = message.getMessagePublishInfo();

-            exchangeName = pb.getExchange();

-            routingKey = pb.getRoutingKey();

-        }

-        else

-        {

-            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);

-            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());

-            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());

-        }

-

-        final boolean isRedelivered = entry.isRedelivered();

-

-        final AMQBody returnBlock = new AMQBody()

-        {

-

-            public AMQBody _underlyingBody;

-

-            public AMQBody createAMQBody()

-            {

-                return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,

-                                                              deliveryTag,

-                                                              isRedelivered,

-                                                              exchangeName,

-                                                              routingKey);

-

-

-

-

-

-            }

-

-            public byte getFrameType()

-            {

-                return AMQMethodBody.TYPE;

-            }

-

-            public int getSize()

-            {

-                if(_underlyingBody == null)

-                {

-                    _underlyingBody = createAMQBody();

-                }

-                return _underlyingBody.getSize();

-            }

-

-            public void writePayload(DataOutputStream buffer) throws IOException

-            {

-                if(_underlyingBody == null)

-                {

-                    _underlyingBody = createAMQBody();

-                }

-                _underlyingBody.writePayload(buffer);

-            }

-

-            public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)

-                throws AMQException

-            {

-                throw new AMQException("This block should never be dispatched!");

-            }

-        };

-        return returnBlock;

-    }

-

-    private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)

-            throws AMQException

-    {

-        final AMQShortString exchangeName;

-        final AMQShortString routingKey;

-

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            final AMQMessage message = (AMQMessage) entry.getMessage();

-            final MessagePublishInfo pb = message.getMessagePublishInfo();

-            exchangeName = pb.getExchange();

-            routingKey = pb.getRoutingKey();

-        }

-        else

-        {

-            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);

-            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());

-            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());

-        }

-

-        final boolean isRedelivered = entry.isRedelivered();

-

-        BasicGetOkBody getOkBody =

-                METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,

-                                                    isRedelivered,

-                                                    exchangeName,

-                                                    routingKey,

-                                                    queueSize);

-

-        return getOkBody;

-    }

-

-    public byte getProtocolMinorVersion()

-    {

-        return getProtocolSession().getProtocolMinorVersion();

-    }

-

-    public byte getProtocolMajorVersion()

-    {

-        return getProtocolSession().getProtocolMajorVersion();

-    }

-

-    private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,

-                                             int replyCode,

-                                             AMQShortString replyText) throws AMQException

-    {

-

-        BasicReturnBody basicReturnBody =

-                METHOD_REGISTRY.createBasicReturnBody(replyCode,

-                                                     replyText,

-                                                     messagePublishInfo.getExchange(),

-                                                     messagePublishInfo.getRoutingKey());

-

-

-        return basicReturnBody;

-    }

-

-    public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)

-            throws AMQException

-    {

-

-        AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);

-

-        writeMessageDelivery(message, header, channelId, returnFrame);

-    }

-

-

-    public void writeFrame(AMQDataBlock block)

-    {

-        getProtocolSession().writeFrame(block);

-    }

-

-

-    public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)

-    {

-

-        BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);

-        writeFrame(basicCancelOkBody.generateFrame(channelId));

-

-    }

-

-

-    public static final class CompositeAMQBodyBlock extends AMQDataBlock

-    {

-        public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();

-

-        private final AMQBody _methodBody;

-        private final AMQBody _headerBody;

-        private final AMQBody _contentBody;

-        private final int _channel;

-

-

-        public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)

-        {

-            _channel = channel;

-            _methodBody = methodBody;

-            _headerBody = headerBody;

-            _contentBody = contentBody;

-

-        }

-

-        public long getSize()

-        {

-            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);

-        }

-    }

-

-    public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock

-    {

-        public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();

-

-        private final AMQBody _methodBody;

-        private final AMQBody _headerBody;

-        private final int _channel;

-

-

-        public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)

-        {

-            _channel = channel;

-            _methodBody = methodBody;

-            _headerBody = headerBody;

-

-        }

-

-        public long getSize()

-        {

-            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);

-        }

-    }

-

-}

+package org.apache.qpid.server.output.amqp0_9;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_9.BasicGetBodyImpl;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
+{
+    private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
+
+
+    public static Factory getInstanceFactory()
+    {
+        return new Factory()
+        {
+
+            public ProtocolOutputConverter newInstance(AMQProtocolSession session)
+            {
+                return new ProtocolOutputConverterImpl(session);
+            }
+        };
+    }
+
+    private final AMQProtocolSession _protocolSession;
+
+    private ProtocolOutputConverterImpl(AMQProtocolSession session)
+    {
+        _protocolSession = session;
+    }
+
+
+    public AMQProtocolSession getProtocolSession()
+    {
+        return _protocolSession;
+    }
+
+    public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
+            throws AMQException
+    {
+        AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
+        writeMessageDelivery(entry, channelId, deliverBody);
+    }
+
+
+    private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+            throws AMQException
+    {
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
+        }
+        else
+        {
+            final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+            ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+            chb.bodySize = message.getSize();
+            return chb;
+        }
+    }
+
+
+    private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)
+            throws AMQException
+    {
+        writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);
+    }
+
+    private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)
+            throws AMQException
+    {
+
+
+        int bodySize = (int) message.getSize();
+
+        if(bodySize == 0)
+        {
+            SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
+                                                                             contentHeaderBody);
+
+            writeFrame(compositeBlock);
+        }
+        else
+        {
+            int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+
+            int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+
+            int writtenSize = capacity;
+
+            AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);
+
+
+            CompositeAMQBodyBlock
+                    compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+            writeFrame(compositeBlock);
+
+            while(writtenSize < bodySize)
+            {
+                capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
+                MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);
+                writtenSize += capacity;
+
+                writeFrame(new AMQFrame(channelId, body));
+            }
+        }
+    }
+
+    private class MessageContentSourceBody implements AMQBody
+    {
+        public static final byte TYPE = 3;
+        private int _length;
+        private MessageContentSource _message;
+        private int _offset;
+
+        public MessageContentSourceBody(MessageContentSource message, int offset, int length)
+        {
+            _message = message;
+            _offset = offset;
+            _length = length;
+        }
+
+        public byte getFrameType()
+        {
+            return TYPE;
+        }
+
+        public int getSize()
+        {
+            return _length;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            byte[] data = new byte[_length];
+
+            _message.getContent(ByteBuffer.wrap(data), _offset);
+
+            buffer.write(data);
+        }
+
+        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
+        {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+
+    private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
+    {
+
+        AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+                                                                      contentHeaderBody);
+        return contentHeader;
+    }
+
+
+    public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
+    {
+        AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
+        writeMessageDelivery(entry, channelId, deliver);
+    }
+
+
+    private AMQBody createEncodedDeliverBody(QueueEntry entry,
+                                              final long deliveryTag,
+                                              final AMQShortString consumerTag)
+            throws AMQException
+    {
+
+        final AMQShortString exchangeName;
+        final AMQShortString routingKey;
+
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            final AMQMessage message = (AMQMessage) entry.getMessage();
+            final MessagePublishInfo pb = message.getMessagePublishInfo();
+            exchangeName = pb.getExchange();
+            routingKey = pb.getRoutingKey();
+        }
+        else
+        {
+            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            DeliveryProperties delvProps = message.getHeader().getDeliveryProperties();
+            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+        }
+
+        final boolean isRedelivered = entry.isRedelivered();
+
+        final AMQBody returnBlock = new AMQBody()
+        {
+
+            public AMQBody _underlyingBody;
+
+            public AMQBody createAMQBody()
+            {
+                return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
+                                                              deliveryTag,
+                                                              isRedelivered,
+                                                              exchangeName,
+                                                              routingKey);
+
+
+
+
+
+            }
+
+            public byte getFrameType()
+            {
+                return AMQMethodBody.TYPE;
+            }
+
+            public int getSize()
+            {
+                if(_underlyingBody == null)
+                {
+                    _underlyingBody = createAMQBody();
+                }
+                return _underlyingBody.getSize();
+            }
+
+            public void writePayload(DataOutput buffer) throws IOException
+            {
+                if(_underlyingBody == null)
+                {
+                    _underlyingBody = createAMQBody();
+                }
+                _underlyingBody.writePayload(buffer);
+            }
+
+            public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
+                throws AMQException
+            {
+                throw new AMQException("This block should never be dispatched!");
+            }
+        };
+        return returnBlock;
+    }
+
+    private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
+            throws AMQException
+    {
+        final AMQShortString exchangeName;
+        final AMQShortString routingKey;
+
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            final AMQMessage message = (AMQMessage) entry.getMessage();
+            final MessagePublishInfo pb = message.getMessagePublishInfo();
+            exchangeName = pb.getExchange();
+            routingKey = pb.getRoutingKey();
+        }
+        else
+        {
+            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            DeliveryProperties delvProps = message.getHeader().getDeliveryProperties();
+            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+        }
+
+        final boolean isRedelivered = entry.isRedelivered();
+
+        BasicGetOkBody getOkBody =
+                METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+                                                    isRedelivered,
+                                                    exchangeName,
+                                                    routingKey,
+                                                    queueSize);
+
+        return getOkBody;
+    }
+
+    public byte getProtocolMinorVersion()
+    {
+        return getProtocolSession().getProtocolMinorVersion();
+    }
+
+    public byte getProtocolMajorVersion()
+    {
+        return getProtocolSession().getProtocolMajorVersion();
+    }
+
+    private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
+                                             int replyCode,
+                                             AMQShortString replyText) throws AMQException
+    {
+
+        BasicReturnBody basicReturnBody =
+                METHOD_REGISTRY.createBasicReturnBody(replyCode,
+                                                     replyText,
+                                                     messagePublishInfo.getExchange(),
+                                                     messagePublishInfo.getRoutingKey());
+
+
+        return basicReturnBody;
+    }
+
+    public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
+            throws AMQException
+    {
+
+        AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
+
+        writeMessageDelivery(message, header, channelId, returnFrame);
+    }
+
+
+    public void writeFrame(AMQDataBlock block)
+    {
+        getProtocolSession().writeFrame(block);
+    }
+
+
+    public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+    {
+
+        BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
+        writeFrame(basicCancelOkBody.generateFrame(channelId));
+
+    }
+
+
+    public static final class CompositeAMQBodyBlock extends AMQDataBlock
+    {
+        public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
+
+        private final AMQBody _methodBody;
+        private final AMQBody _headerBody;
+        private final AMQBody _contentBody;
+        private final int _channel;
+
+
+        public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
+        {
+            _channel = channel;
+            _methodBody = methodBody;
+            _headerBody = headerBody;
+            _contentBody = contentBody;
+
+        }
+
+        public long getSize()
+        {
+            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
+        }
+    }
+
+    public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
+    {
+        public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
+
+        private final AMQBody _methodBody;
+        private final AMQBody _headerBody;
+        private final int _channel;
+
+
+        public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
+        {
+            _channel = channel;
+            _methodBody = methodBody;
+            _headerBody = headerBody;
+
+        }
+
+        public long getSize()
+        {
+            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
+        }
+    }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java
index 1074829..5e2b3e4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/output/amqp0_9_1/ProtocolOutputConverterImpl.java
@@ -1,414 +1,425 @@
-package org.apache.qpid.server.output.amqp0_9_1;

-/*

- *

- * Licensed to the Apache Software Foundation (ASF) under one

- * or more contributor license agreements.  See the NOTICE file

- * distributed with this work for additional information

- * regarding copyright ownership.  The ASF licenses this file

- * to you under the Apache License, Version 2.0 (the

- * "License"); you may not use this file except in compliance

- * with the License.  You may obtain a copy of the License at

- *

- *   http://www.apache.org/licenses/LICENSE-2.0

- *

- * Unless required by applicable law or agreed to in writing,

- * software distributed under the License is distributed on an

- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

- * KIND, either express or implied.  See the License for the

- * specific language governing permissions and limitations

- * under the License.

- *

- */

-

-import org.apache.qpid.server.output.ProtocolOutputConverter;

-import org.apache.qpid.server.output.HeaderPropertiesConverter;

-import org.apache.qpid.server.protocol.AMQProtocolSession;

-import org.apache.qpid.server.message.AMQMessage;

-import org.apache.qpid.server.queue.QueueEntry;

-import org.apache.qpid.server.message.MessageContentSource;

-import org.apache.qpid.server.message.MessageTransferMessage;

-import org.apache.qpid.framing.*;

-import org.apache.qpid.framing.amqp_0_91.BasicGetBodyImpl;

-import org.apache.qpid.framing.abstraction.MessagePublishInfo;

-import org.apache.qpid.AMQException;

-import org.apache.qpid.transport.DeliveryProperties;

-import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;

-

-import java.io.DataOutputStream;

-import java.io.IOException;

-

-public class ProtocolOutputConverterImpl implements ProtocolOutputConverter

-{

-    private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_91);

-

-    public static Factory getInstanceFactory()

-    {

-        return new Factory()

-        {

-

-            public ProtocolOutputConverter newInstance(AMQProtocolSession session)

-            {

-                return new ProtocolOutputConverterImpl(session);

-            }

-        };

-    }

-

-    private final AMQProtocolSession _protocolSession;

-

-    private ProtocolOutputConverterImpl(AMQProtocolSession session)

-    {

-        _protocolSession = session;

-    }

-

-

-    public AMQProtocolSession getProtocolSession()

-    {

-        return _protocolSession;

-    }

-

-    public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)

-            throws AMQException

-    {

-        AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);

-        writeMessageDelivery(entry, channelId, deliverBody);

-    }

-

-

-    private ContentHeaderBody getContentHeaderBody(QueueEntry entry)

-            throws AMQException

-    {

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            return ((AMQMessage)entry.getMessage()).getContentHeaderBody();

-        }

-        else

-        {

-            final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);

-            ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);

-            chb.bodySize = message.getSize();

-            return chb;

-        }

-    }

-

-

-    private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)

-            throws AMQException

-    {

-        writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);

-    }

-

-    private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)

-            throws AMQException

-    {

-

-

-        int bodySize = (int) message.getSize();

-

-        if(bodySize == 0)

-        {

-            SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,

-                                                                             contentHeaderBody);

-

-            writeFrame(compositeBlock);

-        }

-        else

-        {

-            int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();

-

-

-            int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;

-

-            int writtenSize = capacity;

-

-            AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);

-

-            CompositeAMQBodyBlock

-                    compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);

-            writeFrame(compositeBlock);

-

-            while(writtenSize < bodySize)

-            {

-                capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;

-                MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);

-                writtenSize += capacity;

-

-                writeFrame(new AMQFrame(channelId, body));

-            }

-        }

-    }

-

-    private class MessageContentSourceBody implements AMQBody

-    {

-        public static final byte TYPE = 3;

-        private int _length;

-        private MessageContentSource _message;

-        private int _offset;

-

-        public MessageContentSourceBody(MessageContentSource message, int offset, int length)

-        {

-            _message = message;

-            _offset = offset;

-            _length = length;

-        }

-

-        public byte getFrameType()

-        {

-            return TYPE;

-        }

-

-        public int getSize()

-        {

-            return _length;

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            byte[] data = new byte[_length];

-

-            _message.getContent(java.nio.ByteBuffer.wrap(data), _offset);

-

-            buffer.write(data);

-        }

-

-        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException

-        {

-            throw new UnsupportedOperationException();

-        }

-    }

-

-    private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)

-    {

-

-        AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,

-                                                                      contentHeaderBody);

-        return contentHeader;

-    }

-

-

-    public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException

-    {

-        AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);

-        writeMessageDelivery(entry, channelId, deliver);

-    }

-

-

-    private AMQBody createEncodedDeliverBody(QueueEntry entry,

-                                              final long deliveryTag,

-                                              final AMQShortString consumerTag)

-            throws AMQException

-    {

-

-        final AMQShortString exchangeName;

-        final AMQShortString routingKey;

-

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            final AMQMessage message = (AMQMessage) entry.getMessage();

-            final MessagePublishInfo pb = message.getMessagePublishInfo();

-            exchangeName = pb.getExchange();

-            routingKey = pb.getRoutingKey();

-        }

-        else

-        {

-            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);

-            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());

-            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());

-        }

-

-        final boolean isRedelivered = entry.isRedelivered();

-

-        final AMQBody returnBlock = new AMQBody()

-        {

-

-            public AMQBody _underlyingBody;

-

-            public AMQBody createAMQBody()

-            {

-                return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,

-                                                              deliveryTag,

-                                                              isRedelivered,

-                                                              exchangeName,

-                                                              routingKey);

-

-

-

-

-

-            }

-

-            public byte getFrameType()

-            {

-                return AMQMethodBody.TYPE;

-            }

-

-            public int getSize()

-            {

-                if(_underlyingBody == null)

-                {

-                    _underlyingBody = createAMQBody();

-                }

-                return _underlyingBody.getSize();

-            }

-

-            public void writePayload(DataOutputStream buffer) throws IOException

-            {

-                if(_underlyingBody == null)

-                {

-                    _underlyingBody = createAMQBody();

-                }

-                _underlyingBody.writePayload(buffer);

-            }

-

-            public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)

-                throws AMQException

-            {

-                throw new AMQException("This block should never be dispatched!");

-            }

-        };

-        return returnBlock;

-    }

-

-    private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)

-            throws AMQException

-    {

-        final AMQShortString exchangeName;

-        final AMQShortString routingKey;

-

-        if(entry.getMessage() instanceof AMQMessage)

-        {

-            final AMQMessage message = (AMQMessage) entry.getMessage();

-            final MessagePublishInfo pb = message.getMessagePublishInfo();

-            exchangeName = pb.getExchange();

-            routingKey = pb.getRoutingKey();

-        }

-        else

-        {

-            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();

-            DeliveryProperties delvProps = message.getHeader().get(DeliveryProperties.class);

-            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());

-            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());

-        }

-

-        final boolean isRedelivered = entry.isRedelivered();

-

-        BasicGetOkBody getOkBody =

-                METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,

-                                                    isRedelivered,

-                                                    exchangeName,

-                                                    routingKey,

-                                                    queueSize);

-

-        return getOkBody;

-    }

-

-    public byte getProtocolMinorVersion()

-    {

-        return getProtocolSession().getProtocolMinorVersion();

-    }

-

-    public byte getProtocolMajorVersion()

-    {

-        return getProtocolSession().getProtocolMajorVersion();

-    }

-

-    private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,

-                                             int replyCode,

-                                             AMQShortString replyText) throws AMQException

-    {

-

-        BasicReturnBody basicReturnBody =

-                METHOD_REGISTRY.createBasicReturnBody(replyCode,

-                                                     replyText,

-                                                     messagePublishInfo.getExchange(),

-                                                     messagePublishInfo.getRoutingKey());

-

-

-        return basicReturnBody;

-    }

-

-    public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)

-            throws AMQException

-    {

-

-        AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);

-

-        writeMessageDelivery(message, header, channelId, returnFrame);

-    }

-

-

-    public void writeFrame(AMQDataBlock block)

-    {

-        getProtocolSession().writeFrame(block);

-    }

-

-

-    public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)

-    {

-

-        BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);

-        writeFrame(basicCancelOkBody.generateFrame(channelId));

-

-    }

-

-

-    public static final class CompositeAMQBodyBlock extends AMQDataBlock

-    {

-        public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();

-

-        private final AMQBody _methodBody;

-        private final AMQBody _headerBody;

-        private final AMQBody _contentBody;

-        private final int _channel;

-

-

-        public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)

-        {

-            _channel = channel;

-            _methodBody = methodBody;

-            _headerBody = headerBody;

-            _contentBody = contentBody;

-

-        }

-

-        public long getSize()

-        {

-            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);

-        }

-    }

-

-    public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock

-    {

-        public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();

-

-        private final AMQBody _methodBody;

-        private final AMQBody _headerBody;

-        private final int _channel;

-

-

-        public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)

-        {

-            _channel = channel;

-            _methodBody = methodBody;

-            _headerBody = headerBody;

-

-        }

-

-        public long getSize()

-        {

-            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;

-        }

-

-        public void writePayload(DataOutputStream buffer) throws IOException

-        {

-            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);

-        }

-    }

-

+package org.apache.qpid.server.output.amqp0_9_1;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import org.apache.qpid.server.output.ProtocolOutputConverter;
+import org.apache.qpid.server.output.HeaderPropertiesConverter;
+import org.apache.qpid.server.protocol.AMQProtocolSession;
+import org.apache.qpid.server.message.AMQMessage;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.server.message.MessageTransferMessage;
+import org.apache.qpid.framing.*;
+import org.apache.qpid.framing.amqp_0_91.BasicGetBodyImpl;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.transport.DeliveryProperties;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class ProtocolOutputConverterImpl implements ProtocolOutputConverter
+{
+    private static final MethodRegistry METHOD_REGISTRY = MethodRegistry.getMethodRegistry(ProtocolVersion.v0_91);
+
+    public static Factory getInstanceFactory()
+    {
+        return new Factory()
+        {
+
+            public ProtocolOutputConverter newInstance(AMQProtocolSession session)
+            {
+                return new ProtocolOutputConverterImpl(session);
+            }
+        };
+    }
+
+    private final AMQProtocolSession _protocolSession;
+
+    private ProtocolOutputConverterImpl(AMQProtocolSession session)
+    {
+        _protocolSession = session;
+    }
+
+
+    public AMQProtocolSession getProtocolSession()
+    {
+        return _protocolSession;
+    }
+
+    public void writeDeliver(QueueEntry entry, int channelId, long deliveryTag, AMQShortString consumerTag)
+            throws AMQException
+    {
+        AMQBody deliverBody = createEncodedDeliverBody(entry, deliveryTag, consumerTag);
+        writeMessageDelivery(entry, channelId, deliverBody);
+    }
+
+
+    private ContentHeaderBody getContentHeaderBody(QueueEntry entry)
+            throws AMQException
+    {
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            return ((AMQMessage)entry.getMessage()).getContentHeaderBody();
+        }
+        else
+        {
+            final MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            BasicContentHeaderProperties props = HeaderPropertiesConverter.convert(message);
+            ContentHeaderBody chb = new ContentHeaderBody(props, BasicGetBodyImpl.CLASS_ID);
+            chb.bodySize = message.getSize();
+            return chb;
+        }
+    }
+
+
+    private void writeMessageDelivery(QueueEntry entry, int channelId, AMQBody deliverBody)
+            throws AMQException
+    {
+        writeMessageDelivery(entry.getMessage(), getContentHeaderBody(entry), channelId, deliverBody);
+    }
+
+    private void writeMessageDelivery(MessageContentSource message, ContentHeaderBody contentHeaderBody, int channelId, AMQBody deliverBody)
+            throws AMQException
+    {
+
+
+        int bodySize = (int) message.getSize();
+
+        if(bodySize == 0)
+        {
+            SmallCompositeAMQBodyBlock compositeBlock = new SmallCompositeAMQBodyBlock(channelId, deliverBody,
+                                                                             contentHeaderBody);
+
+            writeFrame(compositeBlock);
+        }
+        else
+        {
+            int maxBodySize = (int) getProtocolSession().getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+
+            int capacity = bodySize > maxBodySize ? maxBodySize : bodySize;
+
+            int writtenSize = capacity;
+
+            AMQBody firstContentBody = new MessageContentSourceBody(message,0,capacity);
+
+            CompositeAMQBodyBlock
+                    compositeBlock = new CompositeAMQBodyBlock(channelId, deliverBody, contentHeaderBody, firstContentBody);
+            writeFrame(compositeBlock);
+
+            while(writtenSize < bodySize)
+            {
+                capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
+                MessageContentSourceBody body = new MessageContentSourceBody(message, writtenSize, capacity);
+                writtenSize += capacity;
+
+                writeFrame(new AMQFrame(channelId, body));
+            }
+        }
+    }
+
+    private class MessageContentSourceBody implements AMQBody
+    {
+        public static final byte TYPE = 3;
+        private int _length;
+        private MessageContentSource _message;
+        private int _offset;
+
+        public MessageContentSourceBody(MessageContentSource message, int offset, int length)
+        {
+            _message = message;
+            _offset = offset;
+            _length = length;
+        }
+
+        public byte getFrameType()
+        {
+            return TYPE;
+        }
+
+        public int getSize()
+        {
+            return _length;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            ByteBuffer buf = _message.getContent(_offset, _length);
+
+            if(buf.hasArray())
+            {
+                buffer.write(buf.array(), buf.arrayOffset()+buf.position(), buf.remaining());
+            }
+            else
+            {
+
+                byte[] data = new byte[_length];
+
+                buf.get(data);
+
+                buffer.write(data);
+            }
+        }
+
+        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
+        {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private AMQDataBlock createContentHeaderBlock(final int channelId, final ContentHeaderBody contentHeaderBody)
+    {
+
+        AMQDataBlock contentHeader = ContentHeaderBody.createAMQFrame(channelId,
+                                                                      contentHeaderBody);
+        return contentHeader;
+    }
+
+
+    public void writeGetOk(QueueEntry entry, int channelId, long deliveryTag, int queueSize) throws AMQException
+    {
+        AMQBody deliver = createEncodedGetOkBody(entry, deliveryTag, queueSize);
+        writeMessageDelivery(entry, channelId, deliver);
+    }
+
+
+    private AMQBody createEncodedDeliverBody(QueueEntry entry,
+                                              final long deliveryTag,
+                                              final AMQShortString consumerTag)
+            throws AMQException
+    {
+
+        final AMQShortString exchangeName;
+        final AMQShortString routingKey;
+
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            final AMQMessage message = (AMQMessage) entry.getMessage();
+            final MessagePublishInfo pb = message.getMessagePublishInfo();
+            exchangeName = pb.getExchange();
+            routingKey = pb.getRoutingKey();
+        }
+        else
+        {
+            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            DeliveryProperties delvProps = message.getHeader().getDeliveryProperties();
+            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+        }
+
+        final boolean isRedelivered = entry.isRedelivered();
+
+        final AMQBody returnBlock = new AMQBody()
+        {
+
+            public AMQBody _underlyingBody;
+
+            public AMQBody createAMQBody()
+            {
+                return METHOD_REGISTRY.createBasicDeliverBody(consumerTag,
+                                                              deliveryTag,
+                                                              isRedelivered,
+                                                              exchangeName,
+                                                              routingKey);
+
+
+
+
+
+            }
+
+            public byte getFrameType()
+            {
+                return AMQMethodBody.TYPE;
+            }
+
+            public int getSize()
+            {
+                if(_underlyingBody == null)
+                {
+                    _underlyingBody = createAMQBody();
+                }
+                return _underlyingBody.getSize();
+            }
+
+            public void writePayload(DataOutput buffer) throws IOException
+            {
+                if(_underlyingBody == null)
+                {
+                    _underlyingBody = createAMQBody();
+                }
+                _underlyingBody.writePayload(buffer);
+            }
+
+            public void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession)
+                throws AMQException
+            {
+                throw new AMQException("This block should never be dispatched!");
+            }
+        };
+        return returnBlock;
+    }
+
+    private AMQBody createEncodedGetOkBody(QueueEntry entry, long deliveryTag, int queueSize)
+            throws AMQException
+    {
+        final AMQShortString exchangeName;
+        final AMQShortString routingKey;
+
+        if(entry.getMessage() instanceof AMQMessage)
+        {
+            final AMQMessage message = (AMQMessage) entry.getMessage();
+            final MessagePublishInfo pb = message.getMessagePublishInfo();
+            exchangeName = pb.getExchange();
+            routingKey = pb.getRoutingKey();
+        }
+        else
+        {
+            MessageTransferMessage message = (MessageTransferMessage) entry.getMessage();
+            DeliveryProperties delvProps = message.getHeader().getDeliveryProperties();
+            exchangeName = (delvProps == null || delvProps.getExchange() == null) ? null : new AMQShortString(delvProps.getExchange());
+            routingKey = (delvProps == null || delvProps.getRoutingKey() == null) ? null : new AMQShortString(delvProps.getRoutingKey());
+        }
+
+        final boolean isRedelivered = entry.isRedelivered();
+
+        BasicGetOkBody getOkBody =
+                METHOD_REGISTRY.createBasicGetOkBody(deliveryTag,
+                                                    isRedelivered,
+                                                    exchangeName,
+                                                    routingKey,
+                                                    queueSize);
+
+        return getOkBody;
+    }
+
+    public byte getProtocolMinorVersion()
+    {
+        return getProtocolSession().getProtocolMinorVersion();
+    }
+
+    public byte getProtocolMajorVersion()
+    {
+        return getProtocolSession().getProtocolMajorVersion();
+    }
+
+    private AMQBody createEncodedReturnFrame(MessagePublishInfo messagePublishInfo,
+                                             int replyCode,
+                                             AMQShortString replyText) throws AMQException
+    {
+
+        BasicReturnBody basicReturnBody =
+                METHOD_REGISTRY.createBasicReturnBody(replyCode,
+                                                     replyText,
+                                                     messagePublishInfo.getExchange(),
+                                                     messagePublishInfo.getRoutingKey());
+
+
+        return basicReturnBody;
+    }
+
+    public void writeReturn(MessagePublishInfo messagePublishInfo, ContentHeaderBody header, MessageContentSource message, int channelId, int replyCode, AMQShortString replyText)
+            throws AMQException
+    {
+
+        AMQBody returnFrame = createEncodedReturnFrame(messagePublishInfo, replyCode, replyText);
+
+        writeMessageDelivery(message, header, channelId, returnFrame);
+    }
+
+
+    public void writeFrame(AMQDataBlock block)
+    {
+        getProtocolSession().writeFrame(block);
+    }
+
+
+    public void confirmConsumerAutoClose(int channelId, AMQShortString consumerTag)
+    {
+
+        BasicCancelOkBody basicCancelOkBody = METHOD_REGISTRY.createBasicCancelOkBody(consumerTag);
+        writeFrame(basicCancelOkBody.generateFrame(channelId));
+
+    }
+
+
+    public static final class CompositeAMQBodyBlock extends AMQDataBlock
+    {
+        public static final int OVERHEAD = 3 * AMQFrame.getFrameOverhead();
+
+        private final AMQBody _methodBody;
+        private final AMQBody _headerBody;
+        private final AMQBody _contentBody;
+        private final int _channel;
+
+
+        public CompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody, AMQBody contentBody)
+        {
+            _channel = channel;
+            _methodBody = methodBody;
+            _headerBody = headerBody;
+            _contentBody = contentBody;
+
+        }
+
+        public long getSize()
+        {
+            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() + _contentBody.getSize();
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody, _contentBody);
+        }
+    }
+
+    public static final class SmallCompositeAMQBodyBlock extends AMQDataBlock
+    {
+        public static final int OVERHEAD = 2 * AMQFrame.getFrameOverhead();
+
+        private final AMQBody _methodBody;
+        private final AMQBody _headerBody;
+        private final int _channel;
+
+
+        public SmallCompositeAMQBodyBlock(int channel, AMQBody methodBody, AMQBody headerBody)
+        {
+            _channel = channel;
+            _methodBody = methodBody;
+            _headerBody = headerBody;
+
+        }
+
+        public long getSize()
+        {
+            return OVERHEAD + _methodBody.getSize() + _headerBody.getSize() ;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            AMQFrame.writeFrames(buffer, _channel, _methodBody, _headerBody);
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index 4e50888..241ab3f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -93,6 +93,7 @@
     // to save boxing the channelId and looking up in a map... cache in an array the low numbered
     // channels.  This value must be of the form 2^x - 1.
     private static final int CHANNEL_CACHE_SIZE = 0xff;
+    private static final int REUSABLE_BYTE_BUFFER_CAPACITY = 65 * 1024;
 
     private AMQShortString _contextKey;
 
@@ -262,6 +263,7 @@
                     closeProtocolSession();
                 }
             }
+            receiveComplete();
         }
         catch (Exception e)
         {
@@ -270,6 +272,15 @@
         }
     }
 
+    private void receiveComplete()
+    {
+        for (AMQChannel channel : _channelMap.values())
+        {
+            channel.receivedComplete();
+        }
+
+    }
+
     public void dataBlockReceived(AMQDataBlock message) throws Exception
     {
         _lastReceived = message;
@@ -387,35 +398,51 @@
         }
     }
 
+
+    private final byte[] _reusableBytes = new byte[REUSABLE_BYTE_BUFFER_CAPACITY];
+    private final ByteBuffer _reusableByteBuffer = ByteBuffer.wrap(_reusableBytes);
+    private final BytesDataOutput _reusableDataOutput = new BytesDataOutput(_reusableBytes);
+
     private ByteBuffer asByteBuffer(AMQDataBlock block)
     {
-        final ByteBuffer buf = ByteBuffer.allocate((int) block.getSize());
+        final int size = (int) block.getSize();
+
+        final byte[] data;
+
+
+        if(size > REUSABLE_BYTE_BUFFER_CAPACITY)
+        {
+            data= new byte[size];
+        }
+        else
+        {
+
+            data = _reusableBytes;
+        }
+        _reusableDataOutput.setBuffer(data);
 
         try
         {
-            block.writePayload(new DataOutputStream(new OutputStream()
-            {
-
-
-                @Override
-                public void write(int b) throws IOException
-                {
-                    buf.put((byte) b);
-                }
-
-                @Override
-                public void write(byte[] b, int off, int len) throws IOException
-                {
-                    buf.put(b, off, len);
-                }
-            }));
+            block.writePayload(_reusableDataOutput);
         }
         catch (IOException e)
         {
             throw new RuntimeException(e);
         }
 
-        buf.flip();
+        final ByteBuffer buf;
+
+        if(size <= REUSABLE_BYTE_BUFFER_CAPACITY)
+        {
+            buf = _reusableByteBuffer;
+            buf.position(0);
+        }
+        else
+        {
+            buf = ByteBuffer.wrap(data);
+        }
+        buf.limit(_reusableDataOutput.length());
+
         return buf;
     }
 
@@ -1418,8 +1445,6 @@
         _deferFlush = deferFlush;
     }
 
-
-
     public String getUserName()
     {
         return getAuthorizedPrincipal().getName();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java
index bc63403..c55fe32 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQSessionModel.java
@@ -22,6 +22,8 @@
 
 import org.apache.qpid.AMQException;
 import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.SimpleAMQQueue;
 
 public interface AMQSessionModel
 {
@@ -51,4 +53,8 @@
      * @param idleClose time in milliseconds before closing connection with idle transaction
      */
     public void checkTransactionStatus(long openWarn, long openClose, long idleWarn, long idleClose) throws AMQException;
+
+    void block(AMQQueue queue);
+
+    void unblock(AMQQueue queue);
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java
index 3faf896..42b49cb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ExchangeDestination.java
@@ -20,17 +20,14 @@
  */
 package org.apache.qpid.server.protocol.v1_0;
 
+import java.util.List;
+import org.apache.qpid.AMQException;
 import org.apache.qpid.amqp_1_0.type.Outcome;
 import org.apache.qpid.amqp_1_0.type.messaging.Accepted;
-
-import org.apache.qpid.AMQException;
 import org.apache.qpid.server.exchange.Exchange;
 import org.apache.qpid.server.queue.BaseQueue;
 import org.apache.qpid.server.txn.ServerTransaction;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-
 public class ExchangeDestination implements ReceivingDestination, SendingDestination
 {
     private static final Accepted ACCEPTED = new Accepted();
@@ -50,7 +47,7 @@
 
     public Outcome send(final Message_1_0 message, ServerTransaction txn)
     {
-        final ArrayList<? extends BaseQueue> queues = _exchange.route(message);
+        final List<? extends BaseQueue> queues = _exchange.route(message);
 
         txn.enqueue(queues,message, new ServerTransaction.Action()
         {
@@ -77,7 +74,7 @@
             {
                 // NO-OP
             }
-        });
+        }, System.currentTimeMillis());
 
         return ACCEPTED;
     }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java
index 5082d70..140a815 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/Message_1_0.java
@@ -21,20 +21,18 @@
 package org.apache.qpid.server.protocol.v1_0;
 
 
+import java.lang.ref.WeakReference;
+import java.nio.ByteBuffer;
+import java.util.List;
+import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.server.configuration.SessionConfig;
-import org.apache.qpid.server.message.AMQMessageHeader;
 import org.apache.qpid.server.message.InboundMessage;
 import org.apache.qpid.server.message.MessageMetaData_1_0;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.store.StoredMessage;
 
-import java.lang.ref.WeakReference;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.List;
-
-public class Message_1_0 implements ServerMessage<Message_1_0>, InboundMessage
+public class Message_1_0 implements ServerMessage, InboundMessage
 {
     private final StoredMessage<MessageMetaData_1_0> _storedMessage;
     private List<ByteBuffer> _fragments;
@@ -63,6 +61,11 @@
         }
     }
 
+    public AMQShortString getRoutingKeyShortString()
+    {
+        return AMQShortString.valueOf(getRoutingKey());
+    }
+
     private MessageMetaData_1_0 getMessageMetaData()
     {
         return _storedMessage.getMetaData();
@@ -73,6 +76,11 @@
         return getMessageMetaData().getMessageHeader();
     }
 
+    public StoredMessage getStoredMessage()
+    {
+        return _storedMessage;
+    }
+
     public boolean isPersistent()
     {
         return getMessageMetaData().isPersistent();
@@ -105,7 +113,7 @@
         return new Reference(this);
     }
 
-    public Long getMessageNumber()
+    public long getMessageNumber()
     {
         return _storedMessage.getMessageNumber();
     }
@@ -120,6 +128,14 @@
         return _storedMessage.getContent(offset, buf);
     }
 
+    public ByteBuffer getContent(int offset, int size)
+    {
+        ByteBuffer buf = ByteBuffer.allocate(size);
+        buf.limit(getContent(buf, offset));
+
+        return buf;
+    }
+
     public SessionConfig getSessionConfig()
     {
         return null;  //TODO
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java
index 5c0143d..c994ac9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/ReceivingLink_1_0.java
@@ -20,6 +20,12 @@
  */
 package org.apache.qpid.server.protocol.v1_0;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import org.apache.qpid.amqp_1_0.messaging.SectionDecoderImpl;
 import org.apache.qpid.amqp_1_0.transport.DeliveryStateHandler;
 import org.apache.qpid.amqp_1_0.transport.LinkEndpoint;
@@ -35,17 +41,12 @@
 import org.apache.qpid.amqp_1_0.type.transport.Detach;
 import org.apache.qpid.amqp_1_0.type.transport.ReceiverSettleMode;
 import org.apache.qpid.amqp_1_0.type.transport.Transfer;
-
 import org.apache.qpid.server.message.MessageMetaData_1_0;
 import org.apache.qpid.server.store.StoredMessage;
 import org.apache.qpid.server.txn.AutoCommitTransaction;
 import org.apache.qpid.server.txn.ServerTransaction;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 
-import java.lang.ref.WeakReference;
-import java.nio.ByteBuffer;
-import java.util.*;
-
 public class ReceivingLink_1_0 implements ReceivingLinkListener, Link_1_0, DeliveryStateHandler
 {
     private VirtualHost _vhost;
@@ -181,7 +182,7 @@
             else
             {
                 Session_1_0 session = getSession();
-                transaction = session != null ? session.getTransaction(null) : new AutoCommitTransaction(_vhost.getTransactionLog());
+                transaction = session != null ? session.getTransaction(null) : new AutoCommitTransaction(_vhost.getMessageStore());
             }
 
             Outcome outcome = _destination.send(message, transaction);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
index 1b335cf..ed9d589 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
@@ -439,7 +439,7 @@
 
                 if(outcome instanceof Accepted)
                 {
-                    AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getTransactionLog());
+                    AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getMessageStore());
                     if(_subscription.acquires())
                     {
                         txn.dequeue(Collections.singleton(queueEntry),
@@ -459,7 +459,7 @@
                 }
                 else if(outcome instanceof Released)
                 {
-                    AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getTransactionLog());
+                    AutoCommitTransaction txn = new AutoCommitTransaction(_vhost.getMessageStore());
                     if(_subscription.acquires())
                     {
                         txn.dequeue(Collections.singleton(queueEntry),
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java
index 0e700dc..a05d148 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/v1_0/TxnCoordinatorLink_1_0.java
@@ -124,7 +124,7 @@
                         }
                         txnId = Integer.valueOf(txnId.intValue() + 1);
 
-                        _openTransactions.put(txnId, new LocalTransaction(_vhost.getTransactionLog()));
+                        _openTransactions.put(txnId, new LocalTransaction(_vhost.getMessageStore()));
 
                         Declared state = new Declared();
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
index 6dfdc5e..32d9c48 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueue.java
@@ -149,7 +149,13 @@
 
     void removeMessagesFromQueue(long fromMessageId, long toMessageId);
 
-
+    static interface Visitor
+    {
+        boolean visit(QueueEntry entry);
+    }
+    
+    void visit(Visitor visitor);
+    
 
     long getMaximumMessageSize();
 
@@ -217,7 +223,7 @@
 
     Map<String, Object> getArguments();
 
-    void checkCapacity(AMQChannel channel);
+    void checkCapacity(AMQSessionModel channel);
 
     /**
      * ExistingExclusiveSubscription signals a failure to create a subscription, because an exclusive subscription
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
index b4765d6..143a6ae 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/AMQQueueMBean.java
@@ -557,7 +557,7 @@
         List<String> list = new ArrayList<String>();
 
         AMQMessageHeader header = msg.getMessageHeader();
-        MessageProperties msgProps = msg.getHeader().get(MessageProperties.class);
+        MessageProperties msgProps = msg.getHeader().getMessageProperties();
 
         String appID = null;
         String userID = null;
@@ -619,7 +619,7 @@
             throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
         }
 
-        ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog());
+        ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getMessageStore());
         _queue.moveMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn);
         txn.commit();
     }
@@ -654,7 +654,7 @@
             throw new OperationsException("\"From MessageId\" should be greater than 0 and less than \"To MessageId\"");
         }
 
-        ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getTransactionLog());
+        ServerTransaction txn = new LocalTransaction(_queue.getVirtualHost().getMessageStore());
 
         _queue.copyMessagesToAnotherQueue(fromMessageId, toMessageId, toQueueName, txn);
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java
index 05e0efd..0bd40e8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/BaseQueue.java
@@ -35,6 +35,7 @@
 
     void enqueue(ServerMessage message) throws AMQException;
     void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException;
+    void enqueue(ServerMessage message, boolean transactional, PostEnqueueAction action) throws AMQException;
 
     boolean isDurable();
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
index c4762c9..ab0a567 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/ConflationQueueList.java
@@ -100,7 +100,7 @@
     {
         if(entry.acquire())
         {
-            ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
+            ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getMessageStore());
             txn.dequeue(entry.getQueue(),entry.getMessage(),
                                     new ServerTransaction.Action()
                                 {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
index 26112d9..31e9725 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/InboundMessageAdapter.java
@@ -23,6 +23,7 @@
 
 import org.apache.qpid.server.message.InboundMessage;
 import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.framing.AMQShortString;
 
 public class InboundMessageAdapter implements InboundMessage
 {
@@ -44,6 +45,11 @@
     }
 
 
+    public AMQShortString getRoutingKeyShortString()
+    {
+        return AMQShortString.valueOf(_entry.getMessage());
+    }
+
     public String getRoutingKey()
     {
         return _entry.getMessage().getRoutingKey();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
index a56f568..19a7a15 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/IncomingMessage.java
@@ -63,7 +63,7 @@
      * delivered. It is <b>cleared after delivery has been attempted</b>. Any persistent record of destinations is done
      * by the message handle.
      */
-    private ArrayList<? extends BaseQueue> _destinationQueues;
+    private List<? extends BaseQueue> _destinationQueues;
 
     private long _expiration;
 
@@ -126,12 +126,18 @@
 
     public MessageMetaData headersReceived()
     {
-        _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0);
+
+        return headersReceived(System.currentTimeMillis());
+    }
+
+    public MessageMetaData headersReceived(long currentTime)
+    {
+        _messageMetaData = new MessageMetaData(_messagePublishInfo, _contentHeaderBody, 0, currentTime);
         return _messageMetaData;
     }
 
 
-    public ArrayList<? extends BaseQueue> getDestinationQueues()
+    public List<? extends BaseQueue> getDestinationQueues()
     {
         return _destinationQueues;
     }
@@ -158,6 +164,11 @@
         return _messagePublishInfo.getExchange();
     }
 
+    public AMQShortString getRoutingKeyShortString()
+    {
+        return _messagePublishInfo.getRoutingKey();
+    }
+
     public String getRoutingKey()
     {
         return _messagePublishInfo.getRoutingKey() == null ? null : _messagePublishInfo.getRoutingKey().toString();
@@ -209,7 +220,7 @@
         return getContentHeader().bodySize;
     }
 
-    public Long getMessageNumber()
+    public long getMessageNumber()
     {
         return _storedMessageHandle.getMessageNumber();
     }
@@ -225,7 +236,7 @@
 
     }
 
-    public void enqueue(final ArrayList<? extends BaseQueue> queues)
+    public void enqueue(final List<? extends BaseQueue> queues)
     {
         _destinationQueues = queues;
     }
@@ -288,6 +299,15 @@
 
     }
 
+
+    public ByteBuffer getContent(int offset, int size)
+    {
+        ByteBuffer buf = ByteBuffer.allocate(size);
+        getContent(buf,offset);
+        buf.flip();
+        return buf;
+    }
+
     public void setStoredMessage(StoredMessage<MessageMetaData> storedMessageHandle)
     {
         _storedMessageHandle = storedMessageHandle;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
index b16d1eb..0220a55 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/OutOfOrderQueue.java
@@ -1,12 +1,14 @@
 package org.apache.qpid.server.queue;
 
 import java.util.Map;
+
 import org.apache.qpid.server.subscription.Subscription;
 import org.apache.qpid.server.subscription.SubscriptionList;
 import org.apache.qpid.server.virtualhost.VirtualHost;
 
 public abstract class OutOfOrderQueue extends SimpleAMQQueue
 {
+
     protected OutOfOrderQueue(String name, boolean durable, String owner,
                               boolean autoDelete, boolean exclusive, VirtualHost virtualHost,
                               QueueEntryListFactory entryListFactory, Map<String, Object> arguments)
@@ -27,11 +29,8 @@
                 QueueContext context = (QueueContext) subscription.getQueueContext();
                 if(context != null)
                 {
-                    QueueEntry subnode = context._lastSeenEntry;
                     QueueEntry released = context._releasedEntry;
-
-                    while(subnode != null && entry.compareTo(subnode) < 0 && !entry.isAcquired()
-                            && (released == null || released.compareTo(entry) > 0))
+                    while(!entry.isAcquired() && (released == null || released.compareTo(entry) > 0))
                     {
                         if(QueueContext._releasedUpdater.compareAndSet(context,released,entry))
                         {
@@ -39,14 +38,11 @@
                         }
                         else
                         {
-                            subnode = context._lastSeenEntry;
                             released = context._releasedEntry;
                         }
-
                     }
                 }
             }
-
         }
     }
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
index 37fad54..142cfdd 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
@@ -75,6 +75,11 @@
         {
             return State.AVAILABLE;
         }
+
+        public String toString()
+        {
+            return getState().name();
+        }
     }
 
 
@@ -85,6 +90,11 @@
         {
             return State.DEQUEUED;
         }
+
+        public String toString()
+        {
+            return getState().name();
+        }
     }
 
 
@@ -95,6 +105,11 @@
         {
             return State.DELETED;
         }
+
+        public String toString()
+        {
+            return getState().name();
+        }
     }
 
     public final class ExpiredState extends EntryState
@@ -104,6 +119,11 @@
         {
             return State.EXPIRED;
         }
+
+        public String toString()
+        {
+            return getState().name();
+        }
     }
 
 
@@ -113,6 +133,11 @@
         {
             return State.ACQUIRED;
         }
+
+        public String toString()
+        {
+            return getState().name();
+        }
     }
 
     public final class SubscriptionAcquiredState extends EntryState
@@ -134,6 +159,11 @@
         {
             return _subscription;
         }
+
+        public String toString()
+        {
+            return "{" + getState().name() + " : " + _subscription +"}";
+        }
     }
 
     public final class SubscriptionAssignedState extends EntryState
@@ -155,6 +185,12 @@
         {
             return _subscription;
         }
+
+
+        public String toString()
+        {
+            return "{" + getState().name() + " : " + _subscription +"}";
+        }
     }
 
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index f1e5042..82c6a2f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -35,6 +35,7 @@
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.subscription.Subscription;
 import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
 import org.apache.qpid.server.txn.ServerTransaction;
 
 public abstract class QueueEntryImpl implements QueueEntry
@@ -420,7 +421,7 @@
             if (rerouteQueues != null && rerouteQueues.size() != 0)
             {
 
-                ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
+                ServerTransaction txn = new LocalTransaction(getQueue().getVirtualHost().getMessageStore());
 
                 txn.enqueue(rerouteQueues, message, new ServerTransaction.Action()
                 {
@@ -443,7 +444,8 @@
                     {
 
                     }
-                });
+                }, 0L);
+
                 txn.dequeue(currentQueue, message, new ServerTransaction.Action()
                 {
                     public void postCommit()
@@ -456,8 +458,10 @@
 
                     }
                 });
-                }
+
+                txn.commit();
             }
+        }
     }
 
     public boolean isQueueDeleted()
@@ -545,4 +549,11 @@
         _deliveryCountUpdater.decrementAndGet(this);
     }
 
+    public String toString()
+    {
+        return "QueueEntryImpl{" +
+                "_entryId=" + _entryId +
+                ", _state=" + _state +
+                '}';
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
index 77c4b91..641aaa0 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
@@ -35,4 +35,6 @@
     Q getHead();
 
     void entryDeleted(Q queueEntry);
+    
+    int getPriorities();
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
index 5270f9f..0d44fe7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/QueueRunner.java
@@ -22,7 +22,6 @@
 
 import org.apache.log4j.Logger;
 import org.apache.qpid.AMQException;
-import org.apache.qpid.pool.ReadWriteRunnable;
 import org.apache.qpid.server.logging.actors.CurrentActor;
 import org.apache.qpid.server.queue.QueueRunner;
 import org.apache.qpid.server.queue.SimpleAMQQueue;
@@ -38,7 +37,7 @@
  * when straight-through delivery of a message to a subscription isn't
  * possible during the enqueue operation.
  */
-public class QueueRunner implements ReadWriteRunnable
+public class QueueRunner implements Runnable
 {
     private static final Logger _logger = Logger.getLogger(QueueRunner.class);
 
@@ -51,13 +50,11 @@
 
     private final AtomicInteger _scheduled = new AtomicInteger(IDLE);
 
-    private static final long ITERATIONS = SimpleAMQQueue.MAX_ASYNC_DELIVERIES;
     private final AtomicBoolean _stateChange = new AtomicBoolean();
 
     private final AtomicLong _lastRunAgain = new AtomicLong();
     private final AtomicLong _lastRunTime = new AtomicLong();
 
-    private long _runs;
     private long _continues;
 
     public QueueRunner(SimpleAMQQueue queue)
@@ -65,8 +62,6 @@
         _queue = queue;
     }
 
-    private int trouble = 0;
-
     public void run()
     {
         if(_scheduled.compareAndSet(SCHEDULED,RUNNING))
@@ -103,16 +98,6 @@
         }
     }
 
-    public boolean isRead()
-    {
-        return false;
-    }
-
-    public boolean isWrite()
-    {
-        return true;
-    }
-
     public String toString()
     {
         return "QueueRunner-" + _queue.getLogActor();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
index 08dab4e..4faca15 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleAMQQueue.java
@@ -18,42 +18,6 @@
  */
 package org.apache.qpid.server.queue;
 
-import org.apache.log4j.Logger;
-
-import org.apache.qpid.AMQException;
-import org.apache.qpid.AMQSecurityException;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.pool.ReadWriteRunnable;
-import org.apache.qpid.pool.ReferenceCountingExecutorService;
-import org.apache.qpid.server.AMQChannel;
-import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
-import org.apache.qpid.server.protocol.AMQSessionModel;
-import org.apache.qpid.server.binding.Binding;
-import org.apache.qpid.server.configuration.ConfigStore;
-import org.apache.qpid.server.configuration.ConfiguredObject;
-import org.apache.qpid.server.configuration.QueueConfigType;
-import org.apache.qpid.server.configuration.QueueConfiguration;
-import org.apache.qpid.server.configuration.SessionConfig;
-import org.apache.qpid.server.exchange.Exchange;
-import org.apache.qpid.server.logging.LogActor;
-import org.apache.qpid.server.logging.LogSubject;
-import org.apache.qpid.server.logging.actors.CurrentActor;
-import org.apache.qpid.server.logging.actors.QueueActor;
-import org.apache.qpid.server.logging.messages.QueueMessages;
-import org.apache.qpid.server.logging.subjects.QueueLogSubject;
-import org.apache.qpid.server.management.ManagedObject;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.AuthorizationHolder;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.subscription.SubscriptionList;
-import org.apache.qpid.server.txn.AutoCommitTransaction;
-import org.apache.qpid.server.txn.LocalTransaction;
-import org.apache.qpid.server.txn.ServerTransaction;
-import org.apache.qpid.server.virtualhost.VirtualHost;
-
-import javax.management.JMException;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -68,11 +32,50 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
+import javax.management.JMException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.AMQSecurityException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.pool.ReferenceCountingExecutorService;
+import org.apache.qpid.server.binding.Binding;
+import org.apache.qpid.server.configuration.ConfigStore;
+import org.apache.qpid.server.configuration.ConfiguredObject;
+import org.apache.qpid.server.configuration.QueueConfigType;
+import org.apache.qpid.server.configuration.QueueConfiguration;
+import org.apache.qpid.server.configuration.SessionConfig;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.QueueActor;
+import org.apache.qpid.server.logging.messages.QueueMessages;
+import org.apache.qpid.server.logging.subjects.QueueLogSubject;
+import org.apache.qpid.server.management.ManagedObject;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.protocol.AMQSessionModel;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.AuthorizationHolder;
+import org.apache.qpid.server.subscription.AssignedSubscriptionMessageGroupManager;
+import org.apache.qpid.server.subscription.DefinedGroupMessageGroupManager;
+import org.apache.qpid.server.subscription.MessageGroupManager;
+import org.apache.qpid.server.subscription.Subscription;
+import org.apache.qpid.server.subscription.SubscriptionList;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.LocalTransaction;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.virtualhost.VirtualHost;
 
-public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener
+public class SimpleAMQQueue implements AMQQueue, Subscription.StateListener, MessageGroupManager.SubscriptionResetHelper
 {
     private static final Logger _logger = Logger.getLogger(SimpleAMQQueue.class);
+    private static final String QPID_GROUP_HEADER_KEY = "qpid.group_header_key";
+    private static final String QPID_SHARED_MSG_GROUP = "qpid.shared_msg_group";
+    private static final String QPID_DEFAULT_MESSAGE_GROUP = "qpid.default-message-group";
+    private static final String QPID_NO_GROUP = "qpid.no-group";
+    // TODO - should make this configurable at the vhost / broker level
+    private static final int DEFAULT_MAX_GROUPS = 255;
 
 
     private final VirtualHost _virtualHost;
@@ -164,7 +167,7 @@
     private AtomicInteger _deliveredMessages = new AtomicInteger();
     private AtomicBoolean _stopped = new AtomicBoolean(false);
 
-    private final ConcurrentMap<AMQChannel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQChannel, Boolean>();
+    private final ConcurrentMap<AMQSessionModel, Boolean> _blockedChannels = new ConcurrentHashMap<AMQSessionModel, Boolean>();
 
     private final AtomicBoolean _deleted = new AtomicBoolean(false);
     private final List<Task> _deleteTaskList = new CopyOnWriteArrayList<Task>();
@@ -190,6 +193,7 @@
 
     /** the maximum delivery count for each message on this queue or 0 if maximum delivery count is not to be enforced. */
     private int _maximumDeliveryCount = ApplicationRegistry.getInstance().getConfiguration().getMaxDeliveryCount();
+    private final MessageGroupManager _messageGroupManager;
 
     protected SimpleAMQQueue(AMQShortString name, boolean durable, AMQShortString owner, boolean autoDelete, boolean exclusive, VirtualHost virtualHost, Map<String,Object> arguments)
     {
@@ -245,25 +249,15 @@
         _logSubject = new QueueLogSubject(this);
         _logActor = new QueueActor(this, CurrentActor.get().getRootMessageLogger());
 
-        // Log the correct creation message
-
-        // Extract the number of priorities for this Queue.
-        // Leave it as 0 if we are a SimpleQueueEntryList
-        int priorities = 0;
-        if (entryListFactory instanceof PriorityQueueList.Factory)
-        {
-            priorities = ((PriorityQueueList)_entries).getPriorities();
-        }
-
         // Log the creation of this Queue.
         // The priorities display is toggled on if we set priorities > 0
         CurrentActor.get().message(_logSubject,
                                    QueueMessages.CREATED(String.valueOf(_owner),
-                                                          priorities,
-                                                          _owner != null,
-                                                          autoDelete,
-                                                          durable, !durable,
-                                                          priorities > 0));
+                                                         _entries.getPriorities(),
+                                                         _owner != null,
+                                                         autoDelete,
+                                                         durable, !durable,
+                                                         _entries.getPriorities() > 0));
 
         getConfigStore().addConfiguredObject(this);
 
@@ -277,6 +271,26 @@
             _logger.error("AMQQueue MBean creation has failed ", e);
         }
 
+        if(arguments != null && arguments.containsKey(QPID_GROUP_HEADER_KEY))
+        {
+            if(arguments.containsKey(QPID_SHARED_MSG_GROUP) && String.valueOf(arguments.get(QPID_SHARED_MSG_GROUP)).equals("1"))
+            {
+                String defaultGroup = String.valueOf(arguments.get(QPID_DEFAULT_MESSAGE_GROUP));
+                _messageGroupManager =
+                        new DefinedGroupMessageGroupManager(String.valueOf(arguments.get(QPID_GROUP_HEADER_KEY)),
+                                defaultGroup == null ? QPID_NO_GROUP : defaultGroup,
+                                this);
+            }
+            else
+            {
+                _messageGroupManager = new AssignedSubscriptionMessageGroupManager(String.valueOf(arguments.get(QPID_GROUP_HEADER_KEY)), DEFAULT_MAX_GROUPS);
+            }
+        }
+        else
+        {
+            _messageGroupManager = null;
+        }
+
         resetNotifications();
 
     }
@@ -292,7 +306,7 @@
 
     // ------ Getters and Setters
 
-    public void execute(ReadWriteRunnable runnable)
+    public void execute(Runnable runnable)
     {
         _asyncDelivery.execute(runnable);
     }
@@ -491,6 +505,11 @@
             setExclusiveSubscriber(null);
             subscription.setQueueContext(null);
 
+            if(_messageGroupManager != null)
+            {
+                resetSubPointersForGroups(subscription, true);
+            }
+
             // auto-delete queues must be deleted if there are no remaining subscribers
 
             if (_autoDelete && getDeleteOnNoConsumers() && !subscription.isTransient() && getConsumerCount() == 0  )
@@ -515,6 +534,34 @@
 
     }
 
+    public void resetSubPointersForGroups(Subscription subscription, boolean clearAssignments)
+    {
+        QueueEntry entry = _messageGroupManager.findEarliestAssignedAvailableEntry(subscription);
+        if(clearAssignments)
+        {
+            _messageGroupManager.clearAssignments(subscription);
+        }
+
+        if(entry != null)
+        {
+            SubscriptionList.SubscriptionNodeIterator subscriberIter = _subscriptionList.iterator();
+            // iterate over all the subscribers, and if they are in advance of this queue entry then move them backwards
+            while (subscriberIter.advance())
+            {
+                Subscription sub = subscriberIter.getNode().getSubscription();
+
+                // we don't make browsers send the same stuff twice
+                if (sub.seesRequeues())
+                {
+                    updateSubRequeueEntry(sub, entry);
+                }
+            }
+
+            deliverAsync();
+
+        }
+    }
+
     public boolean getDeleteOnNoConsumers()
     {
         return _deleteOnNoConsumers;
@@ -592,7 +639,16 @@
 
     public void enqueue(ServerMessage message, PostEnqueueAction action) throws AMQException
     {
-        incrementTxnEnqueueStats(message);
+        enqueue(message, false, action);
+    }
+
+    public void enqueue(ServerMessage message, boolean transactional, PostEnqueueAction action) throws AMQException
+    {
+
+        if(transactional)
+        {
+            incrementTxnEnqueueStats(message);
+        }
         incrementQueueCount();
         incrementQueueSize(message);
 
@@ -689,21 +745,20 @@
         {
             try
             {
-                if (subscriptionReadyAndHasInterest(sub, entry)
-                    && !sub.isSuspended())
+                if (!sub.isSuspended() 
+                    && subscriptionReadyAndHasInterest(sub, entry) 
+                    && mightAssign(sub, entry)
+                    && !sub.wouldSuspend(entry))
                 {
-                    if (!sub.wouldSuspend(entry))
+                    if (sub.acquires() && !(assign(sub, entry) && entry.acquire(sub)))
                     {
-                        if (sub.acquires() && !entry.acquire(sub))
-                        {
-                            // restore credit here that would have been taken away by wouldSuspend since we didn't manage
-                            // to acquire the entry for this subscription
-                            sub.restoreCredit(entry);
-                        }
-                        else
-                        {
-                            deliverMessage(sub, entry, false);
-                        }
+                        // restore credit here that would have been taken away by wouldSuspend since we didn't manage
+                        // to acquire the entry for this subscription
+                        sub.restoreCredit(entry);
+                    }
+                    else
+                    {
+                        deliverMessage(sub, entry, false);
                     }
                 }
             }
@@ -714,6 +769,20 @@
         }
     }
 
+    private boolean assign(final Subscription sub, final QueueEntry entry)
+    {
+        return _messageGroupManager == null || _messageGroupManager.acceptMessage(sub, entry);
+    }
+
+
+    private boolean mightAssign(final Subscription sub, final QueueEntry entry)
+    {
+        if(_messageGroupManager == null || !sub.acquires())
+            return true;
+        Subscription assigned = _messageGroupManager.getAssignedSubscription(entry);
+        return (assigned == null) || (assigned == sub);
+    }
+
     protected void checkSubscriptionsNotAheadOfDelivery(final QueueEntry entry)
     {
         // This method is only required for queues which mess with ordering
@@ -739,13 +808,8 @@
 
     private void incrementTxnEnqueueStats(final ServerMessage message)
     {
-        SessionConfig session = message.getSessionConfig();
-
-        if(session !=null && session.isTransactional())
-        {
-            _msgTxnEnqueues.incrementAndGet();
-            _byteTxnEnqueues.addAndGet(message.getSize());
-        }
+        _msgTxnEnqueues.incrementAndGet();
+        _byteTxnEnqueues.addAndGet(message.getSize());
     }
 
     private void incrementTxnDequeueStats(QueueEntry entry)
@@ -1057,6 +1121,8 @@
         public boolean filterComplete();
     }
 
+
+
     public List<QueueEntry> getMessagesOnTheQueue(final long fromMessageId, final long toMessageId)
     {
         return getMessagesOnTheQueue(new QueueEntryFilter()
@@ -1111,6 +1177,24 @@
 
     }
 
+    public void visit(final Visitor visitor)
+    {
+        QueueEntryIterator queueListIterator = _entries.iterator();
+
+        while(queueListIterator.advance())
+        {
+            QueueEntry node = queueListIterator.getNode();
+
+            if(!node.isDispensed())
+            {
+                if(visitor.visit(node))
+                {
+                    break;
+                }
+            }
+        }
+    }
+
     /**
      * Returns a list of QueEntries from a given range of queue positions, eg messages 5 to 10 on the queue.
      *
@@ -1487,7 +1571,7 @@
                                         {
 
                                         }
-                                    });
+                                    }, 0L);
                         txn.dequeue(this, entry.getMessage(),
                                     new ServerTransaction.Action()
                                     {
@@ -1565,7 +1649,7 @@
         }
     }
 
-    public void checkCapacity(AMQChannel channel)
+    public void checkCapacity(AMQSessionModel channel)
     {
         if(_capacity != 0l)
         {
@@ -1575,10 +1659,9 @@
                 //Overfull log message
                 _logActor.message(_logSubject, QueueMessages.OVERFULL(_atomicQueueSize.get(), _capacity));
 
-                if(_blockedChannels.putIfAbsent(channel, Boolean.TRUE)==null)
-                {
-                    channel.block(this);
-                }
+                _blockedChannels.putIfAbsent(channel, Boolean.TRUE);
+
+                channel.block(this);
 
                 if(_atomicQueueSize.get() <= _flowResumeCapacity)
                 {
@@ -1610,7 +1693,7 @@
                 }
 
 
-                for(AMQChannel c : _blockedChannels.keySet())
+                for(AMQSessionModel c : _blockedChannels.keySet())
                 {
                     c.unblock(this);
                     _blockedChannels.remove(c);
@@ -1752,11 +1835,11 @@
 
             if (node != null && node.isAvailable())
             {
-                if (sub.hasInterest(node))
+                if (sub.hasInterest(node) && mightAssign(sub, node))
                 {
                     if (!sub.wouldSuspend(node))
                     {
-                        if (sub.acquires() && !node.acquire(sub))
+                        if (sub.acquires() && !(assign(sub, node) && node.acquire(sub)))
                         {
                             // restore credit here that would have been taken away by wouldSuspend since we didn't manage
                             // to acquire the entry for this subscription
@@ -1813,7 +1896,8 @@
             QueueEntry node = (releasedNode != null && lastSeen.compareTo(releasedNode)>=0) ? releasedNode : _entries.next(lastSeen);
 
             boolean expired = false;
-            while (node != null && (!node.isAvailable() || (expired = node.expired()) || !sub.hasInterest(node)))
+            while (node != null && (!node.isAvailable() || (expired = node.expired()) || !sub.hasInterest(node) ||
+                                    !mightAssign(sub,node)))
             {
                 if (expired)
                 {
@@ -1841,6 +1925,19 @@
         }
     }
 
+    public boolean isEntryAheadOfSubscription(QueueEntry entry, Subscription sub)
+    {
+        QueueContext context = (QueueContext) sub.getQueueContext();
+        if(context != null)
+        {
+            QueueEntry releasedNode = context._releasedEntry;
+            return releasedNode == null || releasedNode.compareTo(entry) < 0;
+        }
+        else
+        {
+            return false;
+        }
+    }
 
     /**
      * Used by queue Runners to asynchronously deliver messages to consumers.
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
index 0bb5dcc..b40e5a2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SimpleQueueEntryList.java
@@ -185,6 +185,11 @@
         advanceHead();
     }
 
+    public int getPriorities()
+    {
+        return 0;
+    }
+
     static class Factory implements QueueEntryListFactory
     {
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
index 5f8ab16..414a123 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
@@ -51,13 +51,11 @@
         _propertyName = propertyName;
     }
 
-    @Override
     public AMQQueue getQueue()
     {
         return _queue;
     }
 
-    @Override
     public SortedQueueEntryImpl add(final ServerMessage message)
     {
         synchronized(_lock)
@@ -286,7 +284,6 @@
         return (node == null ? Colour.BLACK : node.getColour()) == colour;
     }
 
-    @Override
     public SortedQueueEntryImpl next(final SortedQueueEntryImpl node)
     {
         synchronized(_lock)
@@ -316,13 +313,11 @@
         }
     }
 
-    @Override
     public QueueEntryIterator<SortedQueueEntryImpl> iterator()
     {
         return new QueueEntryIteratorImpl(_head);
     }
 
-    @Override
     public SortedQueueEntryImpl getHead()
     {
         return _head;
@@ -333,7 +328,6 @@
         return _root;
     }
 
-    @Override
     public void entryDeleted(final SortedQueueEntryImpl entry)
     {
         synchronized(_lock)
@@ -431,6 +425,11 @@
         }
     }
 
+    public int getPriorities()
+    {
+        return 0;
+    }
+
     /**
      * Swaps the position of the node in the tree with it's successor
      * (that is the node with the next highest key)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
index fbef23d..48f2efb 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/queue/SubFlushRunner.java
@@ -21,18 +21,17 @@
  */
 
 
-import org.apache.qpid.pool.ReadWriteRunnable;
-import org.apache.qpid.server.subscription.Subscription;
-import org.apache.qpid.server.logging.actors.CurrentActor;
-import org.apache.qpid.AMQException;
-import org.apache.log4j.Logger;
-
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.log4j.Logger;
+import org.apache.qpid.AMQException;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.subscription.Subscription;
 
-class SubFlushRunner implements ReadWriteRunnable
+
+class SubFlushRunner implements Runnable
 {
     private static final Logger _logger = Logger.getLogger(SubFlushRunner.class);
 
@@ -90,16 +89,6 @@
         return (SimpleAMQQueue) _sub.getQueue();
     }
 
-    public boolean isRead()
-    {
-        return false;
-    }
-
-    public boolean isWrite()
-    {
-        return true;
-    }
-
     public String toString()
     {
         return "SubFlushRunner-" + _sub.getLogActor();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index 7eb1b54..6753cf4 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -148,7 +148,7 @@
 
         BrokerConfig broker = new BrokerConfigAdapter(instance);
 
-        SystemConfig system = (SystemConfig) store.getRoot();
+        SystemConfig system = store.getRoot();
         system.addBroker(broker);
         instance.setBroker(broker);
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java
index 6a36b22..f77b8d2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/BrokerConfigAdapter.java
@@ -165,7 +165,6 @@
     /**
      * @see org.apache.qpid.server.configuration.BrokerConfig#getFeatures()
      */
-    @Override
     public List<String> getFeatures()
     {
         final List<String> features = new ArrayList<String>();
@@ -176,4 +175,16 @@
 
         return Collections.unmodifiableList(features);
     }
+
+    @Override
+    public String toString()
+    {
+        return "BrokerConfigAdapter{" +
+               "_id=" + _id +
+               ", _system=" + _system +
+               ", _vhosts=" + _vhosts +
+               ", _createTime=" + _createTime +
+               ", _federationTag='" + _federationTag + '\'' +
+               '}';
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
index abf9e33..2a1ae8a 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
@@ -32,11 +32,9 @@
 
 import java.net.SocketAddress;
 import java.security.Principal;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.security.auth.Subject;
 
@@ -192,6 +190,15 @@
         return _logger;
     }
 
+    private static class CachedPropertiesMap extends LinkedHashMap<String, PublishAccessCheck>
+    {
+        @Override
+        protected boolean removeEldestEntry(Entry<String, PublishAccessCheck> eldest)
+        {
+            return size() >= 200;
+        }
+    }
+
     private abstract class AccessCheck
     {
         abstract Result allowed(SecurityPlugin plugin);
@@ -204,56 +211,61 @@
             return true;
         }
 
-        HashMap<String, SecurityPlugin> remainingPlugins = new HashMap<String, SecurityPlugin>(_globalPlugins);
+        Map<String, SecurityPlugin> remainingPlugins = _globalPlugins.isEmpty()
+                ? Collections.<String, SecurityPlugin>emptyMap()
+                : _hostPlugins.isEmpty() ? _globalPlugins : new HashMap<String, SecurityPlugin>(_globalPlugins);
 		
-		for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet())
+		if(!_hostPlugins.isEmpty())
         {
-		    // Create set of global only plugins
-			SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey());
-			if (globalPlugin != null)
-			{
-				remainingPlugins.remove(hostEntry.getKey());
-			}
-			
-            Result host = checker.allowed(hostEntry.getValue());
-			
-			if (host == Result.DENIED)
-			{
-				// Something vetoed the access, we're done
-				return false;
-			}
-            
-			// host allow overrides global allow, so only check global on abstain or defer
-			if (host != Result.ALLOWED)
-			{
-				if (globalPlugin == null)
-				{
-				    if (host == Result.DEFER)
-				    {
-				        host = hostEntry.getValue().getDefault();
-                    }
-                    if (host == Result.DENIED)
+            for (Entry<String, SecurityPlugin> hostEntry : _hostPlugins.entrySet())
+            {
+                // Create set of global only plugins
+                SecurityPlugin globalPlugin = remainingPlugins.get(hostEntry.getKey());
+                if (globalPlugin != null)
+                {
+                    remainingPlugins.remove(hostEntry.getKey());
+                }
+
+                Result host = checker.allowed(hostEntry.getValue());
+
+                if (host == Result.DENIED)
+                {
+                    // Something vetoed the access, we're done
+                    return false;
+                }
+
+                // host allow overrides global allow, so only check global on abstain or defer
+                if (host != Result.ALLOWED)
+                {
+                    if (globalPlugin == null)
                     {
-                        return false;
+                        if (host == Result.DEFER)
+                        {
+                            host = hostEntry.getValue().getDefault();
+                        }
+                        if (host == Result.DENIED)
+                        {
+                            return false;
+                        }
                     }
-				}
-				else
-				{
-				    Result global = checker.allowed(globalPlugin);
-					if (global == Result.DEFER)
-					{
-					    global = globalPlugin.getDefault();
-					}
-					if (global == Result.ABSTAIN && host == Result.DEFER)
-					{
-					    global = hostEntry.getValue().getDefault();
-					}
-					if (global == Result.DENIED)
+                    else
                     {
-                        return false;
+                        Result global = checker.allowed(globalPlugin);
+                        if (global == Result.DEFER)
+                        {
+                            global = globalPlugin.getDefault();
+                        }
+                        if (global == Result.ABSTAIN && host == Result.DEFER)
+                        {
+                            global = hostEntry.getValue().getDefault();
+                        }
+                        if (global == Result.DENIED)
+                        {
+                            return false;
+                        }
                     }
-				}
-			}
+                }
+            }
         }
 
         for (SecurityPlugin plugin : remainingPlugins.values())
@@ -371,15 +383,41 @@
         });
     }
 
-    public boolean authorisePublish(final boolean immediate, final String routingKey, final String exchangeName)
+
+    private ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> _immediatePublishPropsCache
+            = new ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>>();
+    private ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> _publishPropsCache
+            = new ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>>();
+
+    public boolean authorisePublish(final boolean immediate, String routingKey, String exchangeName)
     {
-        return checkAllPlugins(new AccessCheck()
+        if(routingKey == null)
         {
-            Result allowed(SecurityPlugin plugin)
+            routingKey = "";
+        }
+        if(exchangeName == null)
+        {
+            exchangeName = "";
+        }
+        PublishAccessCheck check;
+        ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> cache =
+                immediate ? _immediatePublishPropsCache : _publishPropsCache;
+
+        ConcurrentHashMap<String, PublishAccessCheck> exchangeMap = cache.get(exchangeName);
+        if(exchangeMap == null)
+        {
+            cache.putIfAbsent(exchangeName, new ConcurrentHashMap<String, PublishAccessCheck>());
+            exchangeMap = cache.get(exchangeName);
+        }
+
+            check = exchangeMap.get(routingKey);
+            if(check == null)
             {
-                return plugin.authorise(PUBLISH, EXCHANGE, new ObjectProperties(exchangeName, routingKey, immediate));
+                check = new PublishAccessCheck(new ObjectProperties(exchangeName, routingKey, immediate));
+                exchangeMap.put(routingKey, check);
             }
-        });
+
+        return checkAllPlugins(check);
     }
 
     public boolean authorisePurge(final AMQQueue queue)
@@ -413,4 +451,19 @@
 
         return current;
     }
+
+    private class PublishAccessCheck extends AccessCheck
+    {
+        private final ObjectProperties _props;
+
+        public PublishAccessCheck(ObjectProperties props)
+        {
+            _props = props;
+        }
+
+        Result allowed(SecurityPlugin plugin)
+        {
+            return plugin.authorise(PUBLISH, EXCHANGE, _props);
+        }
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java
index e4bf8df..8a52d31 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectProperties.java
@@ -18,10 +18,7 @@
  */
 package org.apache.qpid.server.security.access;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.qpid.framing.AMQShortString;
@@ -35,7 +32,7 @@
  * {@link #equals(Object)} and {@link #hashCode()} are intended for use in maps. This is due to the wildcard matching
  * described above.
  */
-public class ObjectProperties extends HashMap<ObjectProperties.Property, String>
+public class ObjectProperties
 {
     /** serialVersionUID */
     private static final long serialVersionUID = -1356019341374170495L;
@@ -93,7 +90,9 @@
 			return properties;
 		}
     }
-	
+
+    private final EnumMap<Property, String> _properties = new EnumMap<Property, String>(Property.class);
+
 	public static List<String> getAllPropertyNames()
     {
 		List<String> properties = new ArrayList<String>();		
@@ -113,7 +112,7 @@
     {
         super();
         
-        putAll(copy);
+        _properties.putAll(copy._properties);
     }
     
     public ObjectProperties(String name)
@@ -231,7 +230,7 @@
 	public List<String> getPropertyNames()
     {
 		List<String> properties = new ArrayList<String>();		
-		for (Property property : keySet())
+		for (Property property : _properties.keySet())
 		{
 			properties.add(property.getName());
 		}
@@ -240,17 +239,22 @@
     
     public Boolean isSet(Property key)
     {
-        return containsKey(key) && Boolean.valueOf(get(key));
+        return _properties.containsKey(key) && Boolean.valueOf(_properties.get(key));
     }
-    
+
+    public String get(Property key)
+    {
+        return _properties.get(key);
+    }
+
     public String getName()
     {
-        return get(Property.NAME);
+        return _properties.get(Property.NAME);
     }
     
     public void setName(String name)
     {
-        put(Property.NAME, name);
+        _properties.put(Property.NAME, name);
     }
     
     public void setName(AMQShortString name)
@@ -262,39 +266,38 @@
     {
         return put(key, value == null ? "" : value.asString());
     }
-    
-    @Override
+
     public String put(Property key, String value)
     {
-        return super.put(key, value == null ? "" : value.trim());
+        return _properties.put(key, value == null ? "" : value.trim());
     }
     
     public void put(Property key, Boolean value)
     {
         if (value != null)
         {
-            super.put(key, Boolean.toString(value));
+            _properties.put(key, Boolean.toString(value));
         }
     }
     
     public boolean matches(ObjectProperties properties)
     {
-        if (properties.keySet().isEmpty())
+        if (properties._properties.keySet().isEmpty())
         {
             return true;
         }
         
-        if (!keySet().containsAll(properties.keySet()))
+        if (!_properties.keySet().containsAll(properties._properties.keySet()))
         {
             return false;
         }
         
-        for (Map.Entry<Property,String> entry : properties.entrySet())
+        for (Map.Entry<Property,String> entry : properties._properties.entrySet())
         {
             Property key = entry.getKey();
             String ruleValue = entry.getValue();
             
-            String thisValue = get(key);
+            String thisValue = _properties.get(key);
 
             if (!valueMatches(thisValue, ruleValue)) 
             {
@@ -315,4 +318,29 @@
                         && thisValue.length() > ruleValue.length()
                         && thisValue.startsWith(ruleValue.substring(0, ruleValue.length() - 2)));
     }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ObjectProperties that = (ObjectProperties) o;
+
+        if (_properties != null ? !_properties.equals(that._properties) : that._properties != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return _properties != null ? _properties.hashCode() : 0;
+    }
+
+    @Override
+    public String toString()
+    {
+        return _properties.toString();
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java
index a883f65..09e7fe0 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/ConfigurationRecoveryHandler.java
@@ -21,6 +21,9 @@
 package org.apache.qpid.server.store;
 
 import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.UUID;
+
 import org.apache.qpid.framing.FieldTable;
 
 public interface ConfigurationRecoveryHandler
@@ -42,7 +45,19 @@
     public static interface BindingRecoveryHandler
     {
         void binding(String exchangeName, String queueName, String bindingKey, ByteBuffer buf);
-        void completeBindingRecovery();
+        BrokerLinkRecoveryHandler completeBindingRecovery();
+    }
+    
+    public static interface BrokerLinkRecoveryHandler
+    {
+        BridgeRecoveryHandler brokerLink(UUID id, long createTime, Map<String,String> arguments);
+        void completeBrokerLinkRecovery();
+    }
+    
+    public static interface BridgeRecoveryHandler
+    {
+        void bridge(UUID id, long createTime, Map<String,String> arguments);
+        void completeBridgeRecoveryForLink();
     }
 
     public static interface QueueEntryRecoveryHandler
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
index d3f46d2..45083c1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DerbyMessageStore.java
@@ -21,7 +21,9 @@
 package org.apache.qpid.server.store;
 
 import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.lang.ref.SoftReference;
@@ -36,7 +38,10 @@
 import java.sql.Statement;
 import java.sql.Types;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.UUID;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -47,11 +52,14 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.federation.Bridge;
+import org.apache.qpid.server.federation.BrokerLink;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.actors.CurrentActor;
 import org.apache.qpid.server.logging.messages.ConfigStoreMessages;
 import org.apache.qpid.server.logging.messages.MessageStoreMessages;
 import org.apache.qpid.server.logging.messages.TransactionLogMessages;
+import org.apache.qpid.server.message.EnqueableMessage;
 import org.apache.qpid.server.queue.AMQQueue;
 
 /**
@@ -60,7 +68,7 @@
  * 
  * TODO extract the SQL statements into a generic JDBC store
  */
-public class DerbyMessageStore implements MessageStore
+public class DerbyMessageStore implements MessageStore, DurableConfigurationStore
 {
 
     private static final Logger _logger = Logger.getLogger(DerbyMessageStore.class);
@@ -80,6 +88,10 @@
     private static final String META_DATA_TABLE_NAME = "QPID_META_DATA";
     private static final String MESSAGE_CONTENT_TABLE_NAME = "QPID_MESSAGE_CONTENT";
 
+    private static final String LINKS_TABLE_NAME = "QPID_LINKS";
+    private static final String BRIDGES_TABLE_NAME = "QPID_BRIDGES";
+
+
     private static final int DB_VERSION = 3;
 
 
@@ -135,6 +147,49 @@
     private static final String DELETE_FROM_META_DATA = "DELETE FROM " + META_DATA_TABLE_NAME + " WHERE message_id = ?";
     private static final String SELECT_ALL_FROM_META_DATA = "SELECT message_id, meta_data FROM " + META_DATA_TABLE_NAME;
 
+    private static final String CREATE_LINKS_TABLE =
+            "CREATE TABLE "+LINKS_TABLE_NAME+" ( id_lsb bigint not null,"
+                                            + " id_msb bigint not null,"
+                                             + " create_time bigint not null,"
+                                             + " arguments blob,  PRIMARY KEY ( id_lsb, id_msb ))";
+    private static final String SELECT_FROM_LINKS =
+            "SELECT create_time, arguments FROM " + LINKS_TABLE_NAME + " WHERE id_lsb = ? and id_msb";
+    private static final String DELETE_FROM_LINKS = "DELETE FROM " + LINKS_TABLE_NAME 
+                                                    + " WHERE id_lsb = ? and id_msb = ?";
+    private static final String SELECT_ALL_FROM_LINKS = "SELECT id_lsb, id_msb, create_time, "
+                                                        + "arguments FROM " + LINKS_TABLE_NAME;
+    private static final String FIND_LINK = "SELECT id_lsb, id_msb FROM " + LINKS_TABLE_NAME + " WHERE id_lsb = ? and"
+                                            + " id_msb = ?";
+    private static final String INSERT_INTO_LINKS = "INSERT INTO " + LINKS_TABLE_NAME + "( id_lsb, "
+                                                  + "id_msb, create_time, arguments ) values (?, ?, ?, ?)";
+
+
+    private static final String CREATE_BRIDGES_TABLE =
+            "CREATE TABLE "+BRIDGES_TABLE_NAME+" ( id_lsb bigint not null,"
+            + " id_msb bigint not null,"
+            + " create_time bigint not null,"
+            + " link_id_lsb bigint not null,"
+            + " link_id_msb bigint not null,"
+            + " arguments blob,  PRIMARY KEY ( id_lsb, id_msb ))";
+    private static final String SELECT_FROM_BRIDGES =
+            "SELECT create_time, link_id_lsb, link_id_msb, arguments FROM " 
+            + BRIDGES_TABLE_NAME + " WHERE id_lsb = ? and id_msb = ?";
+    private static final String DELETE_FROM_BRIDGES = "DELETE FROM " + BRIDGES_TABLE_NAME 
+                                                      + " WHERE id_lsb = ? and id_msb = ?";
+    private static final String SELECT_ALL_FROM_BRIDGES = "SELECT id_lsb, id_msb, " 
+                                                          + " create_time," 
+                                                          + " link_id_lsb, link_id_msb, "
+                                                        + "arguments FROM " + BRIDGES_TABLE_NAME
+                                                        + " WHERE link_id_lsb = ? and link_id_msb = ?";
+    private static final String FIND_BRIDGE = "SELECT id_lsb, id_msb FROM " + BRIDGES_TABLE_NAME +
+                                              " WHERE id_lsb = ? and id_msb = ?";
+    private static final String INSERT_INTO_BRIDGES = "INSERT INTO " + BRIDGES_TABLE_NAME + "( id_lsb, id_msb, "
+                                                    + "create_time, "
+                                                    + "link_id_lsb, link_id_msb, "
+                                                    + "arguments )"
+                                                    + " values (?, ?, ?, ?, ?, ?)";
+
+
     private static final String DERBY_SINGLE_DB_SHUTDOWN_CODE = "08006";
 
 
@@ -197,12 +252,16 @@
                           Configuration storeConfiguration,
                           LogSubject logSubject) throws Exception
     {
-        CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName()));
-
         if(!_configured)
         {
 
             _logSubject = logSubject;
+        }
+
+        CurrentActor.get().message(_logSubject, MessageStoreMessages.CREATED(this.getClass().getName()));
+
+        if(!_configured)
+        {
 
             commonConfiguration(name, storeConfiguration, logSubject);
             _configured = true;
@@ -219,6 +278,11 @@
                           Configuration storeConfiguration,
                           LogSubject logSubject) throws Exception
     {
+
+        if(!_configured)
+        {
+            _logSubject = logSubject;
+        }
         CurrentActor.get().message(_logSubject, TransactionLogMessages.CREATED(this.getClass().getName()));
 
         if(!_configured)
@@ -283,6 +347,8 @@
         createQueueEntryTable(conn);
         createMetaDataTable(conn);
         createMessageContentTable(conn);
+        createLinkTable(conn);
+        createBridgeTable(conn);
 
         conn.close();
     }
@@ -419,6 +485,40 @@
 
     }
 
+    private void createLinkTable(final Connection conn) throws SQLException
+    {
+        if(!tableExists(LINKS_TABLE_NAME, conn))
+        {
+            Statement stmt = conn.createStatement();
+            try
+            {
+                stmt.execute(CREATE_LINKS_TABLE);
+            }
+            finally
+            {
+                stmt.close();
+            }
+        }
+    }
+
+
+    private void createBridgeTable(final Connection conn) throws SQLException
+    {
+        if(!tableExists(BRIDGES_TABLE_NAME, conn))
+        {
+            Statement stmt = conn.createStatement();
+            try
+            {
+                stmt.execute(CREATE_BRIDGES_TABLE);
+            }
+            finally
+            {
+                stmt.close();
+            }
+        }
+    }
+
+
 
 
     private boolean tableExists(final String tableName, final Connection conn) throws SQLException
@@ -459,7 +559,8 @@
             List<String> exchanges = loadExchanges(erh);
             ConfigurationRecoveryHandler.BindingRecoveryHandler brh = erh.completeExchangeRecovery();
             recoverBindings(brh, exchanges);
-            brh.completeBindingRecovery();
+            ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh = brh.completeBindingRecovery();
+            recoverBrokerLinks(lrh);
         }
         catch (SQLException e)
         {
@@ -470,6 +571,144 @@
 
     }
 
+    private void recoverBrokerLinks(final ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler lrh)
+            throws SQLException
+    {
+        _logger.info("Recovering broker links...");
+
+        Connection conn = null;
+        try
+        {
+            conn = newAutoCommitConnection();
+
+            PreparedStatement stmt = conn.prepareStatement(SELECT_ALL_FROM_LINKS);
+
+            try
+            {
+                ResultSet rs = stmt.executeQuery();
+
+                try
+                {
+
+                    while(rs.next())
+                    {
+                        UUID id  = new UUID(rs.getLong(2), rs.getLong(1));
+                        long createTime = rs.getLong(3);
+                        Blob argumentsAsBlob = rs.getBlob(4);
+
+                        byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length());
+                        
+                        DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dataAsBytes));
+                        int size = dis.readInt();
+                        
+                        Map<String,String> arguments = new HashMap<String, String>();
+                        
+                        for(int i = 0; i < size; i++)
+                        {
+                            arguments.put(dis.readUTF(), dis.readUTF());
+                        }
+
+                        ConfigurationRecoveryHandler.BridgeRecoveryHandler brh = lrh.brokerLink(id, createTime, arguments);
+
+                        recoverBridges(brh, id);
+
+                    }
+                }
+                catch (IOException e)
+                {
+                    throw new SQLException(e.getMessage(), e);
+                }
+                finally
+                {
+                    rs.close();
+                }
+            }
+            finally
+            {
+                stmt.close();
+            }
+
+        }
+        finally
+        {
+            if(conn != null)
+            {
+                conn.close();
+            }
+        }
+
+    }
+
+    private void recoverBridges(final ConfigurationRecoveryHandler.BridgeRecoveryHandler brh, final UUID linkId)
+            throws SQLException
+    {
+        _logger.info("Recovering bridges for link " + linkId + "...");
+
+        Connection conn = null;
+        try
+        {
+            conn = newAutoCommitConnection();
+
+            PreparedStatement stmt = conn.prepareStatement(SELECT_ALL_FROM_BRIDGES);
+            stmt.setLong(1, linkId.getLeastSignificantBits());
+            stmt.setLong(2, linkId.getMostSignificantBits());
+
+
+            try
+            {
+                ResultSet rs = stmt.executeQuery();
+
+                try
+                {
+
+                    while(rs.next())
+                    {
+                        UUID id  = new UUID(rs.getLong(2), rs.getLong(1));
+                        long createTime = rs.getLong(3);
+                        Blob argumentsAsBlob = rs.getBlob(6);
+
+                        byte[] dataAsBytes = argumentsAsBlob.getBytes(1,(int) argumentsAsBlob.length());
+
+                        DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dataAsBytes));
+                        int size = dis.readInt();
+
+                        Map<String,String> arguments = new HashMap<String, String>();
+
+                        for(int i = 0; i < size; i++)
+                        {
+                            arguments.put(dis.readUTF(), dis.readUTF());
+                        }
+
+                        brh.bridge(id, createTime, arguments);
+
+                    }
+                    brh.completeBridgeRecoveryForLink();
+                }
+                catch (IOException e)
+                {
+                    throw new SQLException(e.getMessage(), e);
+                }
+                finally
+                {
+                    rs.close();
+                }
+            }
+            finally
+            {
+                stmt.close();
+            }
+
+        }
+        finally
+        {
+            if(conn != null)
+            {
+                conn.close();
+            }
+        }
+
+    }
+
     private void loadQueues(ConfigurationRecoveryHandler.QueueRecoveryHandler qrh) throws SQLException
     {
         Connection conn = newAutoCommitConnection();
@@ -697,7 +936,7 @@
 
                     if (results == 0)
                     {
-                        throw new RuntimeException("Message metadata not found for message id " + messageId);
+                        _logger.warn("Message metadata not found for message id " + messageId);
                     }
 
                     if (_logger.isDebugEnabled())
@@ -1180,6 +1419,233 @@
 
     }
 
+    public void createBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+        _logger.debug("public void createBrokerLink(BrokerLink = " + link + "): called");
+
+        if (_state != State.RECOVERING)
+        {
+            try
+            {
+                Connection conn = newAutoCommitConnection();
+
+                PreparedStatement stmt = conn.prepareStatement(FIND_LINK);
+                try
+                {
+                    
+                    stmt.setLong(1, link.getId().getLeastSignificantBits());
+                    stmt.setLong(2, link.getId().getMostSignificantBits());
+                    ResultSet rs = stmt.executeQuery();
+                    try
+                    {
+
+                        // If we don't have any data in the result set then we can add this queue
+                        if (!rs.next())
+                        {
+                            PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_LINKS);
+
+                            try
+                            {
+                                
+                                insertStmt.setLong(1, link.getId().getLeastSignificantBits());
+                                insertStmt.setLong(2, link.getId().getMostSignificantBits());
+                                insertStmt.setLong(3, link.getCreateTime());
+
+                                byte[] argumentBytes = convertStringMapToBytes(link.getArguments());
+                                ByteArrayInputStream bis = new ByteArrayInputStream(argumentBytes);
+
+                                insertStmt.setBinaryStream(4,bis,argumentBytes.length);
+
+                                insertStmt.execute();
+                            }
+                            finally
+                            {
+                                insertStmt.close();
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        rs.close();
+                    }
+                }
+                finally
+                {
+                    stmt.close();
+                }
+                conn.close();
+
+            }
+            catch (SQLException e)
+            {
+                throw new AMQStoreException("Error writing " + link + " to database: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    private byte[] convertStringMapToBytes(final Map<String, String> arguments) throws AMQStoreException
+    {
+        byte[] argumentBytes;
+        if(arguments == null)
+        {
+            argumentBytes = new byte[0];
+        }
+        else
+        {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            DataOutputStream dos = new DataOutputStream(bos);
+
+
+            try
+            {
+                dos.writeInt(arguments.size());
+                for(Map.Entry<String,String> arg : arguments.entrySet())
+                {
+                    dos.writeUTF(arg.getKey());
+                    dos.writeUTF(arg.getValue());
+                }
+            }
+            catch (IOException e)
+            {
+                // This should never happen
+                throw new AMQStoreException(e.getMessage(), e);
+            }
+            argumentBytes = bos.toByteArray();
+        }
+        return argumentBytes;
+    }
+
+    public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+        _logger.debug("public void deleteBrokerLink( " + link + "): called");
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        try
+        {
+            conn = newAutoCommitConnection();
+            stmt = conn.prepareStatement(DELETE_FROM_LINKS);
+            stmt.setLong(1, link.getId().getLeastSignificantBits());
+            stmt.setLong(2, link.getId().getMostSignificantBits());
+            int results = stmt.executeUpdate();
+
+            if (results == 0)
+            {
+                throw new AMQStoreException("Link " + link + " not found");
+            }
+        }
+        catch (SQLException e)
+        {
+            throw new AMQStoreException("Error deleting Link " + link + " from database: " + e.getMessage(), e);
+        }
+        finally
+        {
+            closePreparedStatement(stmt);
+            closeConnection(conn);
+        }
+
+
+    }
+
+    public void createBridge(final Bridge bridge) throws AMQStoreException
+    {
+        _logger.debug("public void createBridge(BrokerLink = " + bridge + "): called");
+
+        if (_state != State.RECOVERING)
+        {
+            try
+            {
+                Connection conn = newAutoCommitConnection();
+
+                PreparedStatement stmt = conn.prepareStatement(FIND_BRIDGE);
+                try
+                {
+
+                    UUID id = bridge.getId();
+                    stmt.setLong(1, id.getLeastSignificantBits());
+                    stmt.setLong(2, id.getMostSignificantBits());
+                    ResultSet rs = stmt.executeQuery();
+                    try
+                    {
+
+                        // If we don't have any data in the result set then we can add this queue
+                        if (!rs.next())
+                        {
+                            PreparedStatement insertStmt = conn.prepareStatement(INSERT_INTO_BRIDGES);
+
+                            try
+                            {
+
+                                insertStmt.setLong(1, id.getLeastSignificantBits());
+                                insertStmt.setLong(2, id.getMostSignificantBits());
+
+                                insertStmt.setLong(3, bridge.getCreateTime());
+
+                                UUID linkId = bridge.getLink().getId();
+                                insertStmt.setLong(4, linkId.getLeastSignificantBits());
+                                insertStmt.setLong(5, linkId.getMostSignificantBits());
+
+                                byte[] argumentBytes = convertStringMapToBytes(bridge.getArguments());
+                                ByteArrayInputStream bis = new ByteArrayInputStream(argumentBytes);
+
+                                insertStmt.setBinaryStream(6,bis,argumentBytes.length);
+
+                                insertStmt.execute();
+                            }
+                            finally
+                            {
+                                insertStmt.close();
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        rs.close();
+                    }
+                }
+                finally
+                {
+                    stmt.close();
+                }
+                conn.close();
+
+            }
+            catch (SQLException e)
+            {
+                throw new AMQStoreException("Error writing " + bridge + " to database: " + e.getMessage(), e);
+            }
+        }
+    }
+
+    public void deleteBridge(final Bridge bridge) throws AMQStoreException
+    {
+        _logger.debug("public void deleteBridge( " + bridge + "): called");
+        Connection conn = null;
+        PreparedStatement stmt = null;
+        try
+        {
+            conn = newAutoCommitConnection();
+            stmt = conn.prepareStatement(DELETE_FROM_BRIDGES);
+            stmt.setLong(1, bridge.getId().getLeastSignificantBits());
+            stmt.setLong(2, bridge.getId().getMostSignificantBits());
+            int results = stmt.executeUpdate();
+
+            if (results == 0)
+            {
+                throw new AMQStoreException("Bridge " + bridge + " not found");
+            }
+        }
+        catch (SQLException e)
+        {
+            throw new AMQStoreException("Error deleting bridge " + bridge + " from database: " + e.getMessage(), e);
+        }
+        finally
+        {
+            closePreparedStatement(stmt);
+            closeConnection(conn);
+        }
+
+    }
+
     public Transaction newTransaction()
     {
         return new DerbyTransaction();
@@ -1678,14 +2144,26 @@
             }
         }
 
-        public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+        public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
         {
-            DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, messageId);
+            if(message.getStoredMessage() instanceof StoredDerbyMessage)
+            {
+                try
+                {
+                    ((StoredDerbyMessage)message.getStoredMessage()).store(_connWrapper.getConnection());
+                }
+                catch (SQLException e)
+                {
+                    throw new AMQStoreException("Exception on enqueuing message " + _messageId, e);
+                }
+            }
+
+            DerbyMessageStore.this.enqueueMessage(_connWrapper, queue, message.getMessageNumber());
         }
 
-        public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+        public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
         {
-            DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, messageId);
+            DerbyMessageStore.this.dequeueMessage(_connWrapper, queue, message.getMessageNumber());
 
         }
 
@@ -1709,8 +2187,11 @@
     {
 
         private final long _messageId;
+        private StorableMessageMetaData _metaData;
         private volatile SoftReference<StorableMessageMetaData> _metaDataRef;
-        private Connection _conn;
+        private byte[] _data;
+        private volatile SoftReference<byte[]> _dataRef;
+        
 
         StoredDerbyMessage(long messageId, StorableMessageMetaData metaData)
         {
@@ -1721,27 +2202,19 @@
         StoredDerbyMessage(long messageId,
                            StorableMessageMetaData metaData, boolean persist)
         {
-            try
-            {
-                _messageId = messageId;
+            _messageId = messageId;
+            
 
-                _metaDataRef = new SoftReference<StorableMessageMetaData>(metaData);
-                if(persist)
-                {
-                    _conn = newConnection();
-                    storeMetaData(_conn, messageId, metaData);
-                }
-            }
-            catch (SQLException e)
+            _metaDataRef = new SoftReference<StorableMessageMetaData>(metaData);
+            if(persist)
             {
-                throw new RuntimeException(e);
+                _metaData = metaData;    
             }
-
         }
 
         public StorableMessageMetaData getMetaData()
         {
-            StorableMessageMetaData metaData = _metaDataRef.get();
+            StorableMessageMetaData metaData = _metaData == null ? _metaDataRef.get() : _metaData;
             if(metaData == null)
             {
                 try
@@ -1765,27 +2238,62 @@
 
         public void addContent(int offsetInMessage, java.nio.ByteBuffer src)
         {
-            DerbyMessageStore.this.addContent(_conn, _messageId, offsetInMessage, src);
+            src = src.slice();
+
+            if(_data == null)
+            {
+                _data = new byte[src.remaining()];
+                _dataRef = new SoftReference<byte[]>(_data);
+                src.duplicate().get(_data);
+            }
+            else
+            {
+                byte[] oldData = _data;
+                _data = new byte[oldData.length + src.remaining()];
+                _dataRef = new SoftReference<byte[]>(_data);
+
+                System.arraycopy(oldData,0,_data,0,oldData.length);
+                src.duplicate().get(_data, oldData.length, src.remaining());
+            }
+            
         }
 
         public int getContent(int offsetInMessage, java.nio.ByteBuffer dst)
         {
-            return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst);
+            byte[] data = _dataRef == null ? null : _dataRef.get();
+            if(data != null)
+            {
+                int length = Math.min(dst.remaining(), data.length - offsetInMessage);
+                dst.put(data, offsetInMessage, length);
+                return length;
+            }
+            else
+            {
+                return DerbyMessageStore.this.getContent(_messageId, offsetInMessage, dst);
+            }
         }
 
-        public StoreFuture flushToStore()
+
+        public ByteBuffer getContent(int offsetInMessage, int size)
+        {
+            ByteBuffer buf = ByteBuffer.allocate(size);
+            getContent(offsetInMessage, buf);
+            buf.position(0);
+            return  buf;
+        }
+
+        public synchronized StoreFuture flushToStore()
         {
             try
             {
-                if(_conn != null)
+                if(_metaData != null)
                 {
-                    if(_logger.isDebugEnabled())
-                    {
-                        _logger.debug("Flushing message " + _messageId + " to store");
-                    }
+                    Connection conn = newConnection();
+
+                    store(conn);
                     
-                    _conn.commit();
-                    _conn.close();
+                    conn.commit();
+                    conn.close();
                 }
             }
             catch (SQLException e)
@@ -1796,16 +2304,34 @@
                 }
                 throw new RuntimeException(e);
             }
-            finally
-            {
-                _conn = null;
-            }
             return IMMEDIATE_FUTURE;
         }
 
+        private synchronized void store(final Connection conn) throws SQLException
+        {
+            if(_metaData != null)
+            {
+                try
+                {
+                    storeMetaData(conn, _messageId, _metaData);
+                    DerbyMessageStore.this.addContent(conn, _messageId, 0,
+                                                      _data == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(_data));
+                }
+                finally
+                {
+                    _metaData = null;
+                    _data = null;
+                }
+            }
+
+            if(_logger.isDebugEnabled())
+            {
+                _logger.debug("Storing message " + _messageId + " to store");
+            }
+        }
+
         public void remove()
         {
-            flushToStore();
             DerbyMessageStore.this.removeMessage(_messageId);
         }
     }
@@ -1839,4 +2365,5 @@
             }
         }
     }
+
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java
index 5fb2365..9cd2567 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/DurableConfigurationStore.java
@@ -25,6 +25,8 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.federation.Bridge;
+import org.apache.qpid.server.federation.BrokerLink;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.queue.AMQQueue;
 
@@ -128,4 +130,12 @@
      * @throws AMQStoreException If the operation fails for any reason.
      */
     void updateQueue(AMQQueue queue) throws AMQStoreException;
+    
+    void createBrokerLink(BrokerLink link) throws AMQStoreException;
+    
+    void deleteBrokerLink(BrokerLink link) throws AMQStoreException;
+    
+    void createBridge(Bridge bridge) throws AMQStoreException;
+    
+    void deleteBridge(Bridge bridge) throws AMQStoreException;
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
index d008d42..c5393f7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MemoryMessageStore.java
@@ -31,14 +31,18 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.federation.Bridge;
+import org.apache.qpid.server.federation.BrokerLink;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.actors.CurrentActor;
 import org.apache.qpid.server.logging.messages.ConfigStoreMessages;
 import org.apache.qpid.server.logging.messages.MessageStoreMessages;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.queue.AMQQueue;
 
 /** A simple message store that stores the messages in a threadsafe structure in memory. */
-public class MemoryMessageStore implements MessageStore
+public class MemoryMessageStore implements MessageStore, DurableConfigurationStore
 {
     private static final Logger _log = Logger.getLogger(MemoryMessageStore.class);
 
@@ -53,11 +57,11 @@
 
     private static final Transaction IN_MEMORY_TRANSACTION = new Transaction()
     {
-        public void enqueueMessage(TransactionLogResource  queue, Long messageId) throws AMQStoreException
+        public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
         {
         }
 
-        public void dequeueMessage(TransactionLogResource  queue, Long messageId) throws AMQStoreException
+        public void dequeueMessage(TransactionLogResource  queue, EnqueableMessage message) throws AMQStoreException
         {
         }
 
@@ -155,6 +159,26 @@
         // Not required to do anything
     }
 
+    public void createBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+
+    }
+
+    public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+
+    }
+
+    public void createBridge(final Bridge bridge) throws AMQStoreException
+    {
+
+    }
+
+    public void deleteBridge(final Bridge bridge) throws AMQStoreException
+    {
+
+    }
+
     public void configureTransactionLog(String name,
                                         TransactionLogRecoveryHandler recoveryHandler,
                                         Configuration storeConfiguration,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
index e2fca2f..88c95ad 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/MessageStore.java
@@ -20,14 +20,16 @@
  */
 package org.apache.qpid.server.store;
 
+import org.apache.qpid.AMQStoreException;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.commons.configuration.Configuration;
+import org.apache.qpid.server.message.EnqueableMessage;
 
 /**
  * MessageStore defines the interface to a storage area, which can be used to preserve the state of messages.
  *
  */
-public interface MessageStore extends DurableConfigurationStore, TransactionLog
+public interface MessageStore
 {
     StoreFuture IMMEDIATE_FUTURE = new StoreFuture()
         {
@@ -77,4 +79,69 @@
     boolean isPersistent();
 
 
+
+    public static interface Transaction
+    {
+        /**
+         * Places a message onto a specified queue, in a given transactional context.
+         *
+         *
+         *
+         * @param queue     The queue to place the message on.
+         * @param message
+         * @throws org.apache.qpid.AMQStoreException If the operation fails for any reason.
+         */
+        void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException;
+
+        /**
+         * Extracts a message from a specified queue, in a given transactional context.
+         *
+         * @param queue     The queue to place the message on.
+         * @param message The message to dequeue.
+         * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
+         */
+        void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException;
+
+
+        /**
+         * Commits all operations performed within a given transactional context.
+         *
+         * @throws AMQStoreException If the operation fails for any reason.
+         */
+        void commitTran() throws AMQStoreException;
+
+        /**
+         * Commits all operations performed within a given transactional context.
+         *
+         * @throws AMQStoreException If the operation fails for any reason.
+         */
+        StoreFuture commitTranAsync() throws AMQStoreException;
+
+        /**
+         * Abandons all operations performed within a given transactional context.
+         *
+         * @throws AMQStoreException If the operation fails for any reason.
+         */
+        void abortTran() throws AMQStoreException;
+
+
+
+    }
+
+    public void configureTransactionLog(String name,
+                      TransactionLogRecoveryHandler recoveryHandler,
+                      Configuration storeConfiguration,
+                      LogSubject logSubject) throws Exception;
+
+    Transaction newTransaction();
+
+
+
+    public static interface StoreFuture
+    {
+        boolean isComplete();
+
+        void waitForCompletion();
+    }
+
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java
index 2381301..12d2a6a 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StorableMessageMetaData.java
@@ -30,5 +30,7 @@
 
     int writeToBuffer(int offsetInMetaData, ByteBuffer dest);
 
+    int getContentSize();
+
     boolean isPersistent();
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java
index fba4745..144cc62 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMemoryMessage.java
@@ -42,36 +42,87 @@
 
     public void addContent(int offsetInMessage, ByteBuffer src)
     {
-        src = src.duplicate();
-        if(_content == null || offsetInMessage + src.remaining() > _content.capacity())
+        if(_content == null)
         {
-            ByteBuffer newContent = ByteBuffer.allocate(offsetInMessage+src.remaining());
-            if(_content != null)
+            if(offsetInMessage == 0)
             {
-                newContent.duplicate().put(_content.array());
+                _content = src.slice();
             }
-            _content = newContent;
+            else
+            {
+                final int contentSize = _metaData.getContentSize();
+                int size = (contentSize < offsetInMessage + src.remaining())
+                        ? offsetInMessage + src.remaining()
+                        : contentSize;
+                _content = ByteBuffer.allocate(size);
+                addContent(offsetInMessage, src);
+            }
         }
+        else
+        {
+            if(_content.limit() >= offsetInMessage + src.remaining())
+            {
+                _content.position(offsetInMessage);
+                _content.put(src);
+                _content.position(0);
+            }
+            else
+            {
+                final int contentSize = _metaData.getContentSize();
+                int size = (contentSize < offsetInMessage + src.remaining())
+                        ? offsetInMessage + src.remaining()
+                        : contentSize;
+                ByteBuffer oldContent = _content;
+                _content = ByteBuffer.allocate(size);
+                _content.put(oldContent);
+                _content.position(0);
+                addContent(offsetInMessage, src);
+            }
 
-        ByteBuffer dst = _content.duplicate();
-        dst.position(offsetInMessage);
-        dst.put(src);
+        }
     }
 
     public int getContent(int offset, ByteBuffer dst)
     {
-        ByteBuffer src = _content.duplicate();
-        src.position(offset);
-        src = src.slice();
-        if(dst.remaining() < src.limit())
+        if(_content == null)
         {
-            src.limit(dst.remaining());
+            return 0;
         }
+        ByteBuffer src = _content.duplicate();
+
+        int oldPosition = src.position();
+
+        src.position(oldPosition + offset);
+
+        int length = dst.remaining() < src.remaining() ? dst.remaining() : src.remaining();
+        src.limit(oldPosition + length);
+
         dst.put(src);
-        return src.limit();
+
+
+        return length;
     }
 
-    public TransactionLog.StoreFuture flushToStore()
+
+    public ByteBuffer getContent(int offsetInMessage, int size)
+    {
+        if(_content == null)
+        {
+            return null;
+        }
+        ByteBuffer buf = _content.duplicate();
+
+        if(offsetInMessage != 0)
+        {
+            buf.position(offsetInMessage);
+            buf = buf.slice();
+        }
+
+        buf.limit(size);
+        return buf;
+    }
+
+    public MessageStore.StoreFuture flushToStore()
     {
         return MessageStore.IMMEDIATE_FUTURE;
     }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java
index 0bc45c6..d4a0381 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/StoredMessage.java
@@ -32,7 +32,9 @@
 
     int getContent(int offsetInMessage, ByteBuffer dst);
 
-    TransactionLog.StoreFuture flushToStore();
+    ByteBuffer getContent(int offsetInMessage, int size);
+
+    MessageStore.StoreFuture flushToStore();
 
     void remove();
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java
index d196a91..da7f8d1 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLog.java
@@ -20,72 +20,7 @@
  */
 package org.apache.qpid.server.store;
 
-import org.apache.qpid.server.logging.LogSubject;
-import org.apache.qpid.AMQStoreException;
-import org.apache.commons.configuration.Configuration;
-
 public interface TransactionLog
 {
 
-    public static interface Transaction
-    {
-        /**
-         * Places a message onto a specified queue, in a given transactional context.
-         *
-         * @param queue     The queue to place the message on.
-         * @param messageId The message to enqueue.
-         * @throws AMQStoreException If the operation fails for any reason.
-         */
-        void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException;
-
-        /**
-         * Extracts a message from a specified queue, in a given transactional context.
-         *
-         * @param queue     The queue to place the message on.
-         * @param messageId The message to dequeue.
-         * @throws AMQStoreException If the operation fails for any reason, or if the specified message does not exist.
-         */
-        void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException;
-
-
-        /**
-         * Commits all operations performed within a given transactional context.
-         *
-         * @throws AMQStoreException If the operation fails for any reason.
-         */
-        void commitTran() throws AMQStoreException;
-
-        /**
-         * Commits all operations performed within a given transactional context.
-         *
-         * @throws AMQStoreException If the operation fails for any reason.
-         */
-        StoreFuture commitTranAsync() throws AMQStoreException;
-
-        /**
-         * Abandons all operations performed within a given transactional context.
-         *
-         * @throws AMQStoreException If the operation fails for any reason.
-         */
-        void abortTran() throws AMQStoreException;
-
-
-
-    }
-
-    public void configureTransactionLog(String name,
-                      TransactionLogRecoveryHandler recoveryHandler,
-                      Configuration storeConfiguration,
-                      LogSubject logSubject) throws Exception;
-
-    Transaction newTransaction();
-
-
-
-    public static interface StoreFuture
-    {
-        boolean isComplete();
-
-        void waitForCompletion();
-    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java
index 7781c52..802596e 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/store/TransactionLogRecoveryHandler.java
@@ -22,7 +22,7 @@
 
 public interface TransactionLogRecoveryHandler
 {
-    QueueEntryRecoveryHandler begin(TransactionLog log);
+    QueueEntryRecoveryHandler begin(MessageStore log);
 
     public static interface QueueEntryRecoveryHandler
     {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java
new file mode 100644
index 0000000..f511cc0
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/AssignedSubscriptionMessageGroupManager.java
@@ -0,0 +1,150 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+
+
+public class AssignedSubscriptionMessageGroupManager implements MessageGroupManager
+{
+    private static final Logger _logger = LoggerFactory.getLogger(AssignedSubscriptionMessageGroupManager.class);
+
+
+    private final String _groupId;
+    private final ConcurrentHashMap<Integer, Subscription> _groupMap = new ConcurrentHashMap<Integer, Subscription>();
+    private final int _groupMask;
+
+    public AssignedSubscriptionMessageGroupManager(final String groupId, final int maxGroups)
+    {
+        _groupId = groupId;
+        _groupMask = pow2(maxGroups)-1;
+    }
+
+    private static int pow2(final int i)
+    {
+        int val = 1;
+        while(val < i) val<<=1;
+        return val;
+    }
+
+    public Subscription getAssignedSubscription(final QueueEntry entry)
+    {
+        Object groupVal = entry.getMessage().getMessageHeader().getHeader(_groupId);
+        return groupVal == null ? null : _groupMap.get(groupVal.hashCode() & _groupMask);
+    }
+
+    public boolean acceptMessage(Subscription sub, QueueEntry entry)
+    {
+        Object groupVal = entry.getMessage().getMessageHeader().getHeader(_groupId);
+        if(groupVal == null)
+        {
+            return true;
+        }
+        else
+        {
+            Integer group = groupVal.hashCode() & _groupMask;
+            Subscription assignedSub = _groupMap.get(group);
+            if(assignedSub == sub)
+            {
+                return true;
+            }
+            else
+            {
+                if(assignedSub == null)
+                {
+                    if(_logger.isDebugEnabled())
+                    {
+                        _logger.debug("Assigning group " + groupVal + " to sub " + sub);
+                    }
+                    assignedSub = _groupMap.putIfAbsent(group, sub);
+                    return assignedSub == null || assignedSub == sub;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+        }
+    }
+    
+    public QueueEntry findEarliestAssignedAvailableEntry(Subscription sub)
+    {
+        EntryFinder visitor = new EntryFinder(sub);
+        sub.getQueue().visit(visitor);
+        return visitor.getEntry();
+    }
+
+    private class EntryFinder implements AMQQueue.Visitor
+    {
+        private QueueEntry _entry;
+        private Subscription _sub;
+
+        public EntryFinder(final Subscription sub)
+        {
+            _sub = sub;
+        }
+
+        public boolean visit(final QueueEntry entry)
+        {
+            if(!entry.isAvailable())
+                return false;
+
+            Object groupId = entry.getMessage().getMessageHeader().getHeader(_groupId);
+            if(groupId == null)
+                return false;
+
+            Integer group = groupId.hashCode() & _groupMask;
+            Subscription assignedSub = _groupMap.get(group);
+            if(assignedSub == _sub)
+            {
+                _entry = entry;
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public QueueEntry getEntry()
+        {
+            return _entry;
+        }
+    }
+
+    public void clearAssignments(Subscription sub)
+    {
+        Iterator<Subscription> subIter = _groupMap.values().iterator();
+        while(subIter.hasNext())
+        {
+            if(subIter.next() == sub)
+            {
+                subIter.remove();
+            }
+        }
+    }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java
new file mode 100644
index 0000000..42818db
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/DefinedGroupMessageGroupManager.java
@@ -0,0 +1,270 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.AMQQueue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DefinedGroupMessageGroupManager implements MessageGroupManager
+{
+    private static final Logger _logger = LoggerFactory.getLogger(DefinedGroupMessageGroupManager.class);
+
+    private final String _groupId;
+    private final String _defaultGroup;
+    private final Map<Object, Group> _groupMap = new HashMap<Object, Group>();
+    private final SubscriptionResetHelper _resetHelper;
+
+    private final class Group
+    {
+        private final Object _group;
+        private Subscription _subscription;
+        private int _activeCount;
+
+        private Group(final Object key, final Subscription subscription)
+        {
+            _group = key;
+            _subscription = subscription;
+        }
+        
+        public boolean add()
+        {
+            if(_subscription != null)
+            {
+                _activeCount++;
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+        
+        public void subtract()
+        {
+            if(--_activeCount == 0)
+            {
+                _resetHelper.resetSubPointersForGroups(_subscription, false);
+                _subscription = null;
+                _groupMap.remove(_group);
+            }
+        }
+
+        @Override
+        public boolean equals(final Object o)
+        {
+            if (this == o)
+            {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass())
+            {
+                return false;
+            }
+
+            Group group = (Group) o;
+
+            return _group.equals(group._group);
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return _group.hashCode();
+        }
+
+        public boolean isValid()
+        {
+            return !(_subscription == null || (_activeCount == 0 && _subscription.isClosed()));
+        }
+
+        public Subscription getSubscription()
+        {
+            return _subscription;
+        }
+
+        @Override
+        public String toString()
+        {
+            return "Group{" +
+                    "_group=" + _group +
+                    ", _subscription=" + _subscription +
+                    ", _activeCount=" + _activeCount +
+                    '}';
+        }
+    }
+
+    public DefinedGroupMessageGroupManager(final String groupId, String defaultGroup, SubscriptionResetHelper resetHelper)
+    {
+        _groupId = groupId;
+        _defaultGroup = defaultGroup;
+        _resetHelper = resetHelper;
+    }
+    
+    public synchronized Subscription getAssignedSubscription(final QueueEntry entry)
+    {
+        Object groupId = getKey(entry);
+
+        Group group = _groupMap.get(groupId);
+        return group == null || !group.isValid() ? null : group.getSubscription();
+    }
+
+    public synchronized boolean acceptMessage(final Subscription sub, final QueueEntry entry)
+    {
+        Object groupId = getKey(entry);
+        Group group = _groupMap.get(groupId);
+        
+        if(group == null || !group.isValid())
+        {
+            group = new Group(groupId, sub);
+
+            _groupMap.put(groupId, group);
+
+            // there's a small change that the group became empty between the point at which getNextAvailable() was
+            // called on the subscription, and when accept message is called... in that case we want to avoid delivering
+            // out of order
+            if(_resetHelper.isEntryAheadOfSubscription(entry, sub))
+            {
+                return false;
+            }
+
+        }
+        
+        Subscription assignedSub = group.getSubscription();
+        
+        if(assignedSub == sub)
+        {
+            entry.addStateChangeListener(new GroupStateChangeListener(group, entry));
+            return true;
+        }
+        else
+        {
+            return false;            
+        }
+    }
+    
+    
+    public synchronized QueueEntry findEarliestAssignedAvailableEntry(final Subscription sub)
+    {
+        EntryFinder visitor = new EntryFinder(sub);
+        sub.getQueue().visit(visitor);
+        _logger.debug("Earliest available entry for " + sub + " is " + visitor.getEntry() + (visitor.getEntry() == null ? "" : " : " + getKey(visitor.getEntry())));
+        return visitor.getEntry();
+    }
+
+    private class EntryFinder implements AMQQueue.Visitor
+    {
+        private QueueEntry _entry;
+        private Subscription _sub;
+
+        public EntryFinder(final Subscription sub)
+        {
+            _sub = sub;
+        }
+
+        public boolean visit(final QueueEntry entry)
+        {
+            if(!entry.isAvailable())
+                return false;
+
+            Object groupId = getKey(entry);
+
+            Group group = _groupMap.get(groupId);
+            if(group != null && group.getSubscription() == _sub)
+            {
+                _entry = entry;
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public QueueEntry getEntry()
+        {
+            return _entry;
+        }
+    }
+
+    
+    public void clearAssignments(final Subscription sub)
+    {
+    }
+    
+    private Object getKey(QueueEntry entry)
+    {
+        ServerMessage message = entry.getMessage();
+        AMQMessageHeader messageHeader = message == null ? null : message.getMessageHeader();
+        Object groupVal = messageHeader == null ? _defaultGroup : messageHeader.getHeader(_groupId);
+        if(groupVal == null)
+        {
+            groupVal = _defaultGroup;
+        }
+        return groupVal;
+    }
+
+    private class GroupStateChangeListener implements QueueEntry.StateChangeListener
+    {
+        private final Group _group;
+
+        public GroupStateChangeListener(final Group group,
+                                        final QueueEntry entry)
+        {
+            _group = group;
+        }
+
+        public void stateChanged(final QueueEntry entry,
+                                 final QueueEntry.State oldState,
+                                 final QueueEntry.State newState)
+        {
+            synchronized (DefinedGroupMessageGroupManager.this)
+            {
+                if(_group.isValid())
+                {
+                    if(oldState != newState)
+                    {
+                        if(newState == QueueEntry.State.ACQUIRED)
+                        {
+                            _logger.debug("Adding to " + _group);
+                            _group.add();
+                        }
+                        else if(oldState == QueueEntry.State.ACQUIRED)
+                        {
+                            _logger.debug("Subtracting from " + _group);
+                            _group.subtract();
+                        }
+                    }
+                }
+                else
+                {
+                    entry.removeStateChangeListener(this);
+                }
+            }
+        }
+    }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageGroupManager.java
new file mode 100644
index 0000000..8ce4ce3
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/MessageGroupManager.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.server.subscription;
+
+import org.apache.qpid.server.queue.QueueEntry;
+
+public interface MessageGroupManager
+{
+    public interface SubscriptionResetHelper
+    {
+        public void resetSubPointersForGroups(Subscription subscription, boolean clearAssignments);
+
+        boolean isEntryAheadOfSubscription(QueueEntry entry, Subscription sub);
+    }
+
+    Subscription getAssignedSubscription(QueueEntry entry);
+
+    boolean acceptMessage(Subscription sub, QueueEntry entry);
+
+    QueueEntry findEarliestAssignedAvailableEntry(Subscription sub);
+
+    void clearAssignments(Subscription sub);
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
index 6db58ce..1e36119 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/subscription/Subscription_0_10.java
@@ -62,7 +62,6 @@
 import org.apache.qpid.transport.MessageTransfer;
 import org.apache.qpid.transport.Method;
 import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.Session;
 import org.apache.qpid.transport.Struct;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.BasicContentHeaderProperties;
@@ -70,10 +69,10 @@
 import org.apache.qpid.AMQException;
 
 import java.text.MessageFormat;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.locks.Lock;
@@ -183,6 +182,7 @@
             throw new IllegalStateException("Attempt to set queue for subscription " + this + " to " + queue + "when already set to " + getQueue());
         }
         _queue = queue;
+
         Map<String, Object> arguments = queue.getArguments() == null ? Collections.EMPTY_MAP : queue.getArguments();
         _traceExclude = (String) arguments.get("qpid.trace.exclude");
         _trace = (String) arguments.get("qpid.trace.id");
@@ -219,8 +219,8 @@
 
         if (_noLocal && entry.getMessage() instanceof MessageTransferMessage)
         {
-            Session messageSession= ((MessageTransferMessage)entry.getMessage()).getSession();
-            if (messageSession != null && messageSession.getConnection() == _session.getConnection())
+            Object connectionRef = ((MessageTransferMessage)entry.getMessage()).getConnectionReference();
+            if (connectionRef != null && connectionRef == _session.getReference())
             {
                 return false;
             }
@@ -366,35 +366,8 @@
         {
 
             MessageTransferMessage msg = (MessageTransferMessage) serverMsg;
-
-
-            Struct[] headers;
-            if(msg.getHeader() == null)
-            {
-                headers = EMPTY_STRUCT_ARRAY;
-            }
-            else
-            {
-                headers = msg.getHeader().getStructs();
-            }
-
-            ArrayList<Struct> newHeaders = new ArrayList<Struct>(headers.length);
-            DeliveryProperties origDeliveryProps = null;
-            for(Struct header : headers)
-            {
-                if(header instanceof DeliveryProperties)
-                {
-                    origDeliveryProps = (DeliveryProperties) header;
-                }
-                else
-                {
-                    if(header instanceof MessageProperties)
-                    {
-                        messageProps = (MessageProperties) header;
-                    }
-                    newHeaders.add(header);
-                }
-            }
+            DeliveryProperties origDeliveryProps = msg.getHeader() == null ? null : msg.getHeader().getDeliveryProperties();
+            messageProps = msg.getHeader() == null ? null : msg.getHeader().getMessageProperties();
 
             deliveryProps = new DeliveryProperties();
             if(origDeliveryProps != null)
@@ -429,17 +402,16 @@
 
             deliveryProps.setRedelivered(entry.isRedelivered());
 
-            newHeaders.add(deliveryProps);
-
             if(_trace != null && messageProps == null)
             {
                 messageProps = new MessageProperties();
-                newHeaders.add(messageProps);
             }
 
-            Header header = new Header(newHeaders);
+            Header header = new Header(deliveryProps, messageProps, msg.getHeader() == null ? null : msg.getHeader().getNonStandardProperties());
 
-            xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody());
+
+            xfr = batch ? new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody(), BATCHED)
+                        : new MessageTransfer(_destination,_acceptMode,_acquireMode,header,msg.getBody());
         }
         else if(serverMsg instanceof AMQMessage)
         {
@@ -452,8 +424,6 @@
             message_0_8.getContent(body, 0);
             body.flip();
 
-            Struct[] headers = new Struct[] { deliveryProps, messageProps };
-
             BasicContentHeaderProperties properties =
                     (BasicContentHeaderProperties) message_0_8.getContentHeaderBody().getProperties();
             final AMQShortString exchange = message_0_8.getMessagePublishInfo().getExchange();
@@ -494,8 +464,9 @@
 
             messageProps.setApplicationHeaders(appHeaders);
 
-            Header header = new Header(headers);
-            xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body);
+            Header header = new Header(deliveryProps, messageProps, null);
+            xfr = batch ? new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body, BATCHED)
+                        : new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body);
         }
         else
         {
@@ -508,8 +479,6 @@
             serverMsg.getContent(body, 0);
             body.flip();
 
-            Struct[] headers = new Struct[] { deliveryProps, messageProps };
-
 
             deliveryProps.setExpiration(serverMsg.getExpiration());
             deliveryProps.setImmediate(serverMsg.isImmediate());
@@ -556,8 +525,9 @@
 
             messageProps.setApplicationHeaders(appHeaders);
 */
-            Header header = new Header(headers);
-            xfr = new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body);
+            Header header = new Header(deliveryProps, messageProps, null);
+            xfr = batch ? new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body, BATCHED)
+                        : new MessageTransfer(_destination,_acceptMode,_acquireMode,header, body);
         }
 
         boolean excludeDueToFederation = false;
@@ -633,27 +603,46 @@
         }
     }
 
+    private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit)
+    {
+        _deferredMessageCredit += deferredMessageCredit;
+        _deferredSizeCredit += deferredSizeCredit;
+
+    }
+
+    public void flushCreditState(boolean strict)
+    {
+        if(strict || !isSuspended() || _deferredMessageCredit >= 200
+          || !(_creditManager instanceof WindowCreditManager)
+          || ((WindowCreditManager)_creditManager).getMessageCreditLimit() < 400 )
+        {
+            _creditManager.restoreCredit(_deferredMessageCredit, _deferredSizeCredit);
+            _deferredMessageCredit = 0;
+            _deferredSizeCredit = 0l;
+        }
+    }
+
     private void forceDequeue(final QueueEntry entry, final boolean restoreCredit)
     {
-        ServerTransaction txn = new AutoCommitTransaction(getQueue().getVirtualHost().getTransactionLog());
-        txn.dequeue(entry.getQueue(),entry.getMessage(),
-                                new ServerTransaction.Action()
-                            {
-                                public void postCommit()
-                                {
-                                    if(restoreCredit)
-                                    {
-                                        restoreCredit(entry);
-                                    }
-                                    entry.discard();
-                                }
+        AutoCommitTransaction dequeueTxn = new AutoCommitTransaction(getQueue().getVirtualHost().getMessageStore()); 
+        dequeueTxn.dequeue(entry.getQueue(), entry.getMessage(),
+                           new ServerTransaction.Action()
+                           {
+                               public void postCommit()
+                               {
+                                   if (restoreCredit)
+                                   {
+                                       restoreCredit(entry);
+                                   }
+                                   entry.discard();
+                               }
 
-                                public void onRollback()
-                                {
+                               public void onRollback()
+                               {
 
-                                }
-                            });
-    }
+                               }
+                           });
+   }
 
     void reject(final QueueEntry entry)
     {
@@ -693,7 +682,7 @@
         {
             final InboundMessage m = new InboundMessageAdapter(entry);
 
-            final ArrayList<? extends BaseQueue> destinationQueues = alternateExchange.route(m);
+            final List<? extends BaseQueue> destinationQueues = alternateExchange.route(m);
 
             if (destinationQueues == null || destinationQueues.isEmpty())
             {
@@ -740,6 +729,7 @@
         return _stateChangeLock.tryLock();
     }
 
+
     public void getSendLock()
     {
         _stateChangeLock.lock();
@@ -800,28 +790,6 @@
         return _properties.get(key);
     }
 
-    private void deferredAddCredit(final int deferredMessageCredit, final long deferredSizeCredit)
-    {
-        _deferredMessageCredit += deferredMessageCredit;
-        _deferredSizeCredit += deferredSizeCredit;
-
-    }
-
-    public void flushCreditState()
-    {
-        flushCreditState(false);
-    }
-    public void flushCreditState(boolean strict)
-    {
-        if(strict || !isSuspended() || _deferredMessageCredit >= 200
-          || !(_creditManager instanceof WindowCreditManager)
-          || ((WindowCreditManager)_creditManager).getMessageCreditLimit() < 400 )
-        {
-            _creditManager.restoreCredit(_deferredMessageCredit, _deferredSizeCredit);
-            _deferredMessageCredit = 0;
-            _deferredSizeCredit = 0l;
-        }
-    }
 
     public FlowCreditManager_0_10 getCreditManager()
     {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
index 00f0c9f..ab07ed2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnection.java
@@ -75,7 +75,7 @@
     private boolean _statisticsEnabled = false;
     private StatisticsCounter _messagesDelivered, _dataDelivered, _messagesReceived, _dataReceived;
     private final long _connectionId;
-
+    private final Object _reference = new Object();
     private ServerConnectionMBean _mBean;
     private VirtualHost _virtualHost;
     private AtomicLong _lastIoTime = new AtomicLong();
@@ -90,6 +90,11 @@
         return _config.getId();
     }
 
+    public Object getReference()
+    {
+        return _reference;
+    }
+
     @Override
     protected void invoke(Method method)
     {
@@ -414,13 +419,11 @@
         return _connectionId;
     }
 
-    @Override
     public boolean isSessionNameUnique(byte[] name)
     {
         return !super.hasSessionWithName(name);
     }
 
-    @Override
     public String getUserName()
     {
         return _authorizedPrincipal.getName();
@@ -450,11 +453,11 @@
     {
         for (Session ssn : getChannels())
         {
-            ((ServerSession)ssn).flushCreditState();
+            ((ServerSession)ssn).receivedComplete();
         }
     }
 
-    @Override
+
     public ManagedObject getManagedObject()
     {
         return _mBean;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
index 23b77b1..2142b2f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSession.java
@@ -23,10 +23,8 @@
 import static org.apache.qpid.server.logging.subjects.LogSubjectFormat.CHANNEL_FORMAT;
 import static org.apache.qpid.util.Serial.gt;
 
-import java.lang.ref.WeakReference;
 import java.security.Principal;
 import java.text.MessageFormat;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -34,8 +32,11 @@
 import java.util.SortedMap;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import javax.security.auth.Subject;
 import org.apache.qpid.AMQException;
@@ -51,6 +52,7 @@
 import org.apache.qpid.server.logging.actors.CurrentActor;
 import org.apache.qpid.server.logging.actors.GenericActor;
 import org.apache.qpid.server.logging.messages.ChannelMessages;
+import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.protocol.AMQConnectionModel;
@@ -67,10 +69,16 @@
 import org.apache.qpid.server.virtualhost.VirtualHost;
 import org.apache.qpid.transport.Binary;
 import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.MessageCreditUnit;
+import org.apache.qpid.transport.MessageFlow;
+import org.apache.qpid.transport.MessageFlowMode;
+import org.apache.qpid.transport.MessageSetFlowMode;
+import org.apache.qpid.transport.MessageStop;
 import org.apache.qpid.transport.MessageTransfer;
 import org.apache.qpid.transport.Method;
 import org.apache.qpid.transport.Range;
 import org.apache.qpid.transport.RangeSet;
+import org.apache.qpid.transport.RangeSetFactory;
 import org.apache.qpid.transport.Session;
 import org.apache.qpid.transport.SessionDelegate;
 import org.slf4j.Logger;
@@ -81,11 +89,20 @@
     private static final Logger _logger = LoggerFactory.getLogger(ServerSession.class);
     
     private static final String NULL_DESTINTATION = UUID.randomUUID().toString();
+    private static final int PRODUCER_CREDIT_TOPUP_THRESHOLD = 1 << 30;
 
     private final UUID _id;
     private ConnectionConfig _connectionConfig;
     private long _createTime = System.currentTimeMillis();
     private LogActor _actor = GenericActor.getInstance(this);
+    private PostEnqueueAction _postEnqueueAction = new PostEnqueueAction();
+
+    private final ConcurrentMap<AMQQueue, Boolean> _blockingQueues = new ConcurrentHashMap<AMQQueue, Boolean>();
+
+    private final AtomicBoolean _blocking = new AtomicBoolean(false);
+    private ChannelLogSubject _logSubject;
+    private final AtomicInteger _outstandingCredit = new AtomicInteger(UNLIMITED_CREDIT);
+
 
     public static interface MessageDispositionChangeListener
     {
@@ -121,8 +138,6 @@
 
     private final List<Task> _taskList = new CopyOnWriteArrayList<Task>();
 
-    private final WeakReference<Session> _reference;
-
     ServerSession(Connection connection, SessionDelegate delegate, Binary name, long expiry)
     {
         this(connection, delegate, name, expiry, ((ServerConnection)connection).getConfig());
@@ -133,8 +148,7 @@
         super(connection, delegate, name, expiry);
         _connectionConfig = connConfig;
         _transaction = new AutoCommitTransaction(this.getMessageStore());
-
-        _reference = new WeakReference<Session>(this);
+        _logSubject = new ChannelLogSubject(this);
         _id = getConfigStore().createId();
         getConfigStore().addConfiguredObject(this);
     }
@@ -161,40 +175,28 @@
         return isCommandsFull(id);
     }
 
-    public void enqueue(final ServerMessage message, final ArrayList<? extends BaseQueue> queues)
+    public void enqueue(final ServerMessage message, final List<? extends BaseQueue> queues)
     {
+        if(_outstandingCredit.get() != UNLIMITED_CREDIT
+                && _outstandingCredit.decrementAndGet() == (Integer.MAX_VALUE - PRODUCER_CREDIT_TOPUP_THRESHOLD))
+        {
+            _outstandingCredit.addAndGet(PRODUCER_CREDIT_TOPUP_THRESHOLD);
+            invoke(new MessageFlow("",MessageCreditUnit.MESSAGE, PRODUCER_CREDIT_TOPUP_THRESHOLD));
+        }
         getConnectionModel().registerMessageReceived(message.getSize(), message.getArrivalTime());
-        _transaction.enqueue(queues,message, new ServerTransaction.Action()
-            {
-
-                BaseQueue[] _queues = queues.toArray(new BaseQueue[queues.size()]);
-
-                public void postCommit()
-                {
-                    MessageReference<?> ref = message.newReference();
-                    for(int i = 0; i < _queues.length; i++)
-                    {
-                        try
-                        {
-                            _queues[i].enqueue(message);
-                        }
-                        catch (AMQException e)
-                        {
-                            // TODO
-                            throw new RuntimeException(e);
-                        }
-                    }
-                    ref.release();
-                }
-
-                public void onRollback()
-                {
-                    // NO-OP
-                }
-            });
-
-            incrementOutstandingTxnsIfNecessary();
-            updateTransactionalActivity();
+        PostEnqueueAction postTransactionAction;
+        if(isTransactional())
+        {
+           postTransactionAction = new PostEnqueueAction(queues, message) ;
+        }
+        else
+        {
+            postTransactionAction = _postEnqueueAction;
+            postTransactionAction.setState(queues, message);
+        }
+        _transaction.enqueue(queues,message, postTransactionAction, 0L);
+        incrementOutstandingTxnsIfNecessary();
+        updateTransactionalActivity();
     }
 
 
@@ -252,7 +254,7 @@
 
     public RangeSet acquire(RangeSet transfers)
     {
-        RangeSet acquired = new RangeSet();
+        RangeSet acquired = RangeSetFactory.createRangeSet();
 
         if(!_messageDispositionListenerMap.isEmpty())
         {
@@ -300,41 +302,56 @@
 
     public void dispositionChange(RangeSet ranges, MessageDispositionAction action)
     {
-        if(ranges != null && !_messageDispositionListenerMap.isEmpty())
+        if(ranges != null)
         {
-            Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator();
-            Iterator<Range> rangeIter = ranges.iterator();
 
-            if(rangeIter.hasNext())
+            if(ranges.size() == 1)
             {
-                Range range = rangeIter.next();
-
-                while(range != null && unacceptedMessages.hasNext())
+                Range r = ranges.getFirst();
+                for(int i = r.getLower(); i <= r.getUpper(); i++)
                 {
-                    int next = unacceptedMessages.next();
-                    while(gt(next, range.getUpper()))
+                    MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(i);
+                    if(changeListener != null)
                     {
-                        if(rangeIter.hasNext())
-                        {
-                            range = rangeIter.next();
-                        }
-                        else
-                        {
-                            range = null;
-                            break;
-                        }
-                    }
-                    if(range != null && range.includes(next))
-                    {
-                        MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next);
                         action.performAction(changeListener);
                     }
+                }
+            }
+            else if(!_messageDispositionListenerMap.isEmpty())
+            {
+                Iterator<Integer> unacceptedMessages = _messageDispositionListenerMap.keySet().iterator();
+                Iterator<Range> rangeIter = ranges.iterator();
 
+                if(rangeIter.hasNext())
+                {
+                    Range range = rangeIter.next();
+
+                    while(range != null && unacceptedMessages.hasNext())
+                    {
+                        int next = unacceptedMessages.next();
+                        while(gt(next, range.getUpper()))
+                        {
+                            if(rangeIter.hasNext())
+                            {
+                                range = rangeIter.next();
+                            }
+                            else
+                            {
+                                range = null;
+                                break;
+                            }
+                        }
+                        if(range != null && range.includes(next))
+                        {
+                            MessageDispositionChangeListener changeListener = _messageDispositionListenerMap.remove(next);
+                            action.performAction(changeListener);
+                        }
+
+
+                    }
 
                 }
-
             }
-
         }
     }
 
@@ -534,10 +551,10 @@
         _taskList.remove(task);
     }
 
-    public WeakReference<Session> getReference()
-     {
-         return _reference;
-     }
+    public Object getReference()
+    {
+        return ((ServerConnection) getConnection()).getReference();
+    }
 
     public MessageStore getMessageStore()
     {
@@ -666,13 +683,57 @@
         }
     }
 
+    public void block(AMQQueue queue)
+    {
+        if(_blockingQueues.putIfAbsent(queue, Boolean.TRUE) == null)
+        {
+
+            if(_blocking.compareAndSet(false,true))
+            {
+                invoke(new MessageSetFlowMode("", MessageFlowMode.CREDIT));
+                invoke(new MessageStop(""));
+                _actor.message(_logSubject, ChannelMessages.FLOW_ENFORCED(queue.getNameShortString().toString()));
+            }
+
+
+        }
+    }
+
+    public void unblock(AMQQueue queue)
+    {
+        if(_blockingQueues.remove(queue) && _blockingQueues.isEmpty())
+        {
+            if(_blocking.compareAndSet(true,false))
+            {
+
+                _actor.message(_logSubject, ChannelMessages.FLOW_REMOVED());
+                MessageFlow mf = new MessageFlow();
+                mf.setUnit(MessageCreditUnit.MESSAGE);
+                mf.setDestination("");
+                _outstandingCredit.set(Integer.MAX_VALUE);
+                mf.setValue(Integer.MAX_VALUE);
+                invoke(mf);
+
+
+            }
+        }
+    }
+
+
     public String toLogString()
     {
-       return "[" +
+        long connectionId = getConnection() instanceof ServerConnection
+                            ? ((ServerConnection) getConnection()).getConnectionId()
+                            : -1;
+
+        String remoteAddress = _connectionConfig instanceof ProtocolEngine
+                                ? ((ProtocolEngine) _connectionConfig).getRemoteAddress().toString()
+                                : "";
+        return "[" +
                MessageFormat.format(CHANNEL_FORMAT,
-                                   ((ServerConnection) getConnection()).getConnectionId(),
+                                    connectionId,
                                    getClientID(),
-                                   ((ProtocolEngine) _connectionConfig).getRemoteAddress().toString(),
+                                   remoteAddress,
                                    getVirtualHost().getName(),
                                    getChannel())
             + "] ";
@@ -697,7 +758,7 @@
         }
     }
 
-    public void flushCreditState()
+    public void receivedComplete()
     {
         final Collection<Subscription_0_10> subscriptions = getSubscriptions();
         for (Subscription_0_10 subscription_0_10 : subscriptions)
@@ -706,6 +767,60 @@
         }
     }
 
+    private class PostEnqueueAction implements ServerTransaction.Action
+    {
+
+        private List<? extends BaseQueue> _queues;
+        private ServerMessage _message;
+        private final boolean _transactional;
+
+        public PostEnqueueAction(List<? extends BaseQueue> queues, ServerMessage message)
+        {
+            _transactional = true;
+            setState(queues, message);
+        }
+
+        public PostEnqueueAction()
+        {
+            _transactional = false;
+        }
+
+        public void setState(List<? extends BaseQueue> queues, ServerMessage message)
+        {
+            _message = message;
+            _queues = queues;
+        }
+
+        public void postCommit()
+        {
+            MessageReference<?> ref = _message.newReference();
+            for(int i = 0; i < _queues.size(); i++)
+            {
+                try
+                {
+                    BaseQueue queue = _queues.get(i);
+                    queue.enqueue(_message, _transactional, null);
+                    if(queue instanceof AMQQueue)
+                    {
+                        ((AMQQueue)queue).checkCapacity(ServerSession.this);
+                    }
+
+                }
+                catch (AMQException e)
+                {
+                    // TODO
+                    throw new RuntimeException(e);
+                }
+            }
+            ref.release();
+        }
+
+        public void onRollback()
+        {
+            // NO-OP
+        }
+    }
+
     public int getUnacknowledgedMessageCount()
     {
         return _messageDispositionListenerMap.size();
@@ -713,6 +828,6 @@
 
     public boolean getBlocking()
     {
-        return false; //TODO: Blocking not implemented on 0-10 yet.
+        return _blocking.get();
     }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
index a0dca53..b6e142a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerSessionDelegate.java
@@ -23,6 +23,7 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.log4j.Logger;
@@ -55,46 +56,7 @@
 import org.apache.qpid.server.subscription.SubscriptionFactoryImpl;
 import org.apache.qpid.server.subscription.Subscription_0_10;
 import org.apache.qpid.server.virtualhost.VirtualHost;
-import org.apache.qpid.transport.Acquired;
-import org.apache.qpid.transport.DeliveryProperties;
-import org.apache.qpid.transport.ExchangeBind;
-import org.apache.qpid.transport.ExchangeBound;
-import org.apache.qpid.transport.ExchangeBoundResult;
-import org.apache.qpid.transport.ExchangeDeclare;
-import org.apache.qpid.transport.ExchangeDelete;
-import org.apache.qpid.transport.ExchangeQuery;
-import org.apache.qpid.transport.ExchangeQueryResult;
-import org.apache.qpid.transport.ExchangeUnbind;
-import org.apache.qpid.transport.ExecutionErrorCode;
-import org.apache.qpid.transport.ExecutionException;
-import org.apache.qpid.transport.MessageAccept;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquire;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageCancel;
-import org.apache.qpid.transport.MessageFlow;
-import org.apache.qpid.transport.MessageFlowMode;
-import org.apache.qpid.transport.MessageFlush;
-import org.apache.qpid.transport.MessageReject;
-import org.apache.qpid.transport.MessageRejectCode;
-import org.apache.qpid.transport.MessageRelease;
-import org.apache.qpid.transport.MessageResume;
-import org.apache.qpid.transport.MessageSetFlowMode;
-import org.apache.qpid.transport.MessageStop;
-import org.apache.qpid.transport.MessageSubscribe;
-import org.apache.qpid.transport.MessageTransfer;
-import org.apache.qpid.transport.Method;
-import org.apache.qpid.transport.QueueDeclare;
-import org.apache.qpid.transport.QueueDelete;
-import org.apache.qpid.transport.QueuePurge;
-import org.apache.qpid.transport.QueueQuery;
-import org.apache.qpid.transport.QueueQueryResult;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Session;
-import org.apache.qpid.transport.SessionDelegate;
-import org.apache.qpid.transport.TxCommit;
-import org.apache.qpid.transport.TxRollback;
-import org.apache.qpid.transport.TxSelect;
+import org.apache.qpid.transport.*;
 
 public class ServerSessionDelegate extends SessionDelegate
 {
@@ -295,7 +257,8 @@
         final Exchange exchange = getExchangeForMessage(ssn, xfr);
 
         DeliveryProperties delvProps = null;
-        if(xfr.getHeader() != null && (delvProps = xfr.getHeader().get(DeliveryProperties.class)) != null && delvProps.hasTtl() && !delvProps.hasExpiration())
+        if(xfr.getHeader() != null && (delvProps = xfr.getHeader().getDeliveryProperties()) != null && delvProps.hasTtl() && !delvProps
+                .hasExpiration())
         {
             delvProps.setExpiration(System.currentTimeMillis() + delvProps.getTtl());
         }
@@ -312,7 +275,7 @@
         }
 
         final Exchange exchangeInUse;
-        ArrayList<? extends BaseQueue> queues = exchange.route(messageMetaData);
+        List<? extends BaseQueue> queues = exchange.route(messageMetaData);
         if(queues.isEmpty() && exchange.getAlternateExchange() != null)
         {
             final Exchange alternateExchange = exchange.getAlternateExchange();
@@ -334,15 +297,16 @@
         if(!queues.isEmpty())
         {
             final MessageStore store = getVirtualHost(ssn).getMessageStore();
-            final StoredMessage<MessageMetaData_0_10> storeMessage = createAndFlushStoreMessage(xfr, messageMetaData, store);
+            final StoredMessage<MessageMetaData_0_10> storeMessage = createStoreMessage(xfr, messageMetaData, store);
             MessageTransferMessage message = new MessageTransferMessage(storeMessage, ((ServerSession)ssn).getReference());
             ((ServerSession) ssn).enqueue(message, queues);
+            storeMessage.flushToStore();
         }
         else
         {
             if((delvProps == null || !delvProps.getDiscardUnroutable()) && xfr.getAcceptMode() == MessageAcceptMode.EXPLICIT)
             {
-                RangeSet rejects = new RangeSet();
+                RangeSet rejects = RangeSetFactory.createRangeSet();
                 rejects.add(xfr.getId());
                 MessageReject reject = new MessageReject(rejects, MessageRejectCode.UNROUTABLE, "Unroutable");
                 ssn.invoke(reject);
@@ -353,11 +317,13 @@
             }
         }
 
+
+
         ssn.processed(xfr);
     }
 
-    private StoredMessage<MessageMetaData_0_10> createAndFlushStoreMessage(final MessageTransfer xfr,
-            final MessageMetaData_0_10 messageMetaData, final MessageStore store)
+    private StoredMessage<MessageMetaData_0_10> createStoreMessage(final MessageTransfer xfr,
+                                                                   final MessageMetaData_0_10 messageMetaData, final MessageStore store)
     {
         final StoredMessage<MessageMetaData_0_10> storeMessage = store.addMessage(messageMetaData);
         ByteBuffer body = xfr.getBody();
@@ -365,7 +331,6 @@
         {
             storeMessage.addContent(0, body);
         }
-        storeMessage.flushToStore();
         return storeMessage;
     }
 
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
index 36e9d78..a67d4ba 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/AutoCommitTransaction.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.server.txn;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
@@ -30,7 +31,7 @@
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.queue.BaseQueue;
 import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.MessageStore;
 
 /**
  * An implementation of ServerTransaction where each enqueue/dequeue
@@ -43,11 +44,11 @@
 {
     protected static final Logger _logger = Logger.getLogger(AutoCommitTransaction.class);
 
-    private final TransactionLog _transactionLog;
+    private final MessageStore _messageStore;
 
-    public AutoCommitTransaction(TransactionLog transactionLog)
+    public AutoCommitTransaction(MessageStore transactionLog)
     {
-        _transactionLog = transactionLog;
+        _messageStore = transactionLog;
     }
 
     public long getTransactionStartTime()
@@ -59,14 +60,14 @@
      * Since AutoCommitTransaction have no concept of a long lived transaction, any Actions registered
      * by the caller are executed immediately.
      */
-    public void addPostTransactionAction(Action immediateAction)
+    public void addPostTransactionAction(final Action immediateAction)
     {
         immediateAction.postCommit();
     }
 
     public void dequeue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction)
     {
-        TransactionLog.Transaction txn = null;
+        MessageStore.Transaction txn = null;
         try
         {
             if(message.isPersistent() && queue.isDurable())
@@ -76,8 +77,8 @@
                     _logger.debug("Dequeue of message number " + message.getMessageNumber() + " from transaction log. Queue : " + queue.getNameShortString());
                 }
 
-                txn = _transactionLog.newTransaction();
-                txn.dequeueMessage(queue, message.getMessageNumber());
+                txn = _messageStore.newTransaction();
+                txn.dequeueMessage(queue, message);
                 txn.commitTran();
                 txn = null;
             }
@@ -98,7 +99,7 @@
 
     public void dequeue(Collection<QueueEntry> queueEntries, Action postTransactionAction)
     {
-        TransactionLog.Transaction txn = null;
+        MessageStore.Transaction txn = null;
         try
         {
             for(QueueEntry entry : queueEntries)
@@ -115,10 +116,10 @@
 
                     if(txn == null)
                     {
-                        txn = _transactionLog.newTransaction();
+                        txn = _messageStore.newTransaction();
                     }
 
-                    txn.dequeueMessage(queue, message.getMessageNumber());
+                    txn.dequeueMessage(queue, message);
                 }
 
             }
@@ -145,7 +146,7 @@
 
     public void enqueue(BaseQueue queue, EnqueableMessage message, Action postTransactionAction)
     {
-        TransactionLog.Transaction txn = null;
+        MessageStore.Transaction txn = null;
         try
         {
             if(message.isPersistent() && queue.isDurable())
@@ -155,8 +156,8 @@
                     _logger.debug("Enqueue of message number " + message.getMessageNumber() + " to transaction log. Queue : " + queue.getNameShortString());
                 }
 
-                txn = _transactionLog.newTransaction();
-                txn.enqueueMessage(queue, message.getMessageNumber());
+                txn = _messageStore.newTransaction();
+                txn.enqueueMessage(queue, message);
                 txn.commitTran();
                 txn = null;
             }
@@ -176,15 +177,14 @@
 
     }
 
-    public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction)
+    public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction, long currentTime)
     {
-        TransactionLog.Transaction txn = null;
+        MessageStore.Transaction txn = null;
         try
         {
 
             if(message.isPersistent())
             {
-                Long id = message.getMessageNumber();
                 for(BaseQueue queue : queues)
                 {
                     if (queue.isDurable())
@@ -195,22 +195,26 @@
                         }
                         if (txn == null)
                         {
-                            txn = _transactionLog.newTransaction();
+                            txn = _messageStore.newTransaction();
                         }
                         
-                        txn.enqueueMessage(queue, id);
+                        txn.enqueueMessage(queue, message);
+
+
                     }
                 }
                 
-                if (txn != null)
-                {
-                    txn.commitTran();
-                    txn = null;
-
-                }
             }
+            if (txn != null)
+            {
+                txn.commitTran();
+                txn = null;
+            }
+
             postTransactionAction.postCommit();
             postTransactionAction = null;
+
+
         }
         catch (AMQException e)
         {
@@ -225,6 +229,11 @@
     }
 
 
+    public void commit(final Runnable immediatePostTransactionAction)
+    {
+        immediatePostTransactionAction.run();
+    }    
+    
     public void commit()
     {
     }
@@ -233,7 +242,7 @@
     {
     }
 
-    private void rollbackIfNecessary(Action postTransactionAction, TransactionLog.Transaction txn)
+    private void rollbackIfNecessary(Action postTransactionAction, MessageStore.Transaction txn)
     {
         if (txn != null)
         {
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
index 946dbd7..7f5b5fb 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/LocalTransaction.java
@@ -29,11 +29,7 @@
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.queue.BaseQueue;
 import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.TransactionLog;
-import org.apache.qpid.server.queue.AMQQueue;
-import org.apache.qpid.server.queue.BaseQueue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.MessageStore;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,11 +46,11 @@
 
     private final List<Action> _postTransactionActions = new ArrayList<Action>();
 
-    private volatile TransactionLog.Transaction _transaction;
-    private TransactionLog _transactionLog;
+    private volatile MessageStore.Transaction _transaction;
+    private MessageStore _transactionLog;
     private long _txnStartTime = 0L;
 
-    public LocalTransaction(TransactionLog transactionLog)
+    public LocalTransaction(MessageStore transactionLog)
     {
         _transactionLog = transactionLog;
     }
@@ -63,7 +59,7 @@
     {
         return _transaction != null;
     }
-    
+
     public long getTransactionStartTime()
     {
         return _txnStartTime;
@@ -88,7 +84,7 @@
                 }
 
                 beginTranIfNecessary();
-                _transaction.dequeueMessage(queue, message.getMessageNumber());
+                _transaction.dequeueMessage(queue, message);
 
             }
             catch(AMQException e)
@@ -118,7 +114,7 @@
                     }
 
                     beginTranIfNecessary();
-                    _transaction.dequeueMessage(queue, message.getMessageNumber());
+                    _transaction.dequeueMessage(queue, message);
                 }
 
             }
@@ -191,7 +187,7 @@
                 }
                 
                 beginTranIfNecessary();
-                _transaction.enqueueMessage(queue, message.getMessageNumber());
+                _transaction.enqueueMessage(queue, message);
             }
             catch (Exception e)
             {
@@ -202,13 +198,13 @@
         }
     }
 
-    public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction)
+    public void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction, long currentTime)
     {
         _postTransactionActions.add(postTransactionAction);
 
         if (_txnStartTime == 0L)
         {
-            _txnStartTime = System.currentTimeMillis();
+            _txnStartTime = currentTime == 0L ? System.currentTimeMillis() : currentTime;
         }
 
         if(message.isPersistent())
@@ -226,7 +222,7 @@
                         
                         
                         beginTranIfNecessary();
-                        _transaction.enqueueMessage(queue, message.getMessageNumber());
+                        _transaction.enqueueMessage(queue, message);
                     }
                 }
 
@@ -242,6 +238,11 @@
 
     public void commit()
     {
+        commit(null);
+    }
+
+    public void commit(Runnable immediateAction)
+    {
         try
         {
             if(_transaction != null)
@@ -249,9 +250,14 @@
                 _transaction.commitTran();
             }
 
-            for(Action action : _postTransactionActions)
+            if(immediateAction != null)
             {
-                action.postCommit();
+                immediateAction.run();
+            }
+
+            for(int i = 0; i < _postTransactionActions.size(); i++)
+            {
+                _postTransactionActions.get(i).postCommit();
             }
         }
         catch (Exception e)
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
index b3c6e1a..acdf712 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/txn/ServerTransaction.java
@@ -20,13 +20,12 @@
  */
 package org.apache.qpid.server.txn;
 
+import java.util.Collection;
+import java.util.List;
 import org.apache.qpid.server.message.EnqueableMessage;
 import org.apache.qpid.server.queue.BaseQueue;
 import org.apache.qpid.server.queue.QueueEntry;
 
-import java.util.Collection;
-import java.util.List;
-
 
 /**
  * The ServerTransaction interface allows a set enqueue/dequeue operations to be
@@ -42,7 +41,7 @@
  */
 public interface ServerTransaction
 {
-    /** 
+    /**
      * Represents an action to be performed on transaction commit or rollback
      */
     public static interface Action
@@ -91,7 +90,7 @@
      * 
      * Store operations will result only for a persistent messages on durable queues.
      */
-    void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction);
+    void enqueue(List<? extends BaseQueue> queues, EnqueableMessage message, Action postTransactionAction, long currentTime);
 
     /** 
      * Commit the transaction represented by this object.
@@ -101,6 +100,8 @@
      */
     void commit();
 
+    void commit(Runnable immediatePostTransactionAction);
+
     /** Rollback the transaction represented by this object.
      * 
      * If the caller has registered one or more Actions, the onRollback() method on each will
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
index e8042fc..41a5471 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHost.java
@@ -20,6 +20,7 @@
 */
 package org.apache.qpid.server.virtualhost;
 
+import java.util.Map;
 import java.util.UUID;
 
 import org.apache.qpid.common.Closeable;
@@ -40,7 +41,6 @@
 import org.apache.qpid.server.stats.StatisticsGatherer;
 import org.apache.qpid.server.store.DurableConfigurationStore;
 import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.TransactionLog;
 
 public interface VirtualHost extends DurableConfigurationStore.Source, VirtualHostConfig, Closeable, StatisticsGatherer
 {
@@ -58,8 +58,6 @@
 
     MessageStore getMessageStore();
 
-    TransactionLog getTransactionLog();
-
     DurableConfigurationStore getDurableConfigurationStore();
 
     AuthenticationManager getAuthenticationManager();
@@ -95,6 +93,8 @@
                                 boolean durable,
                                 String authMechanism, String username, String password);
 
+    public BrokerLink createBrokerConnection(UUID id, long createTime, Map<String,String> arguments);
+
     ConfigStore getConfigStore();
 
     void removeBrokerConnection(BrokerLink brokerLink);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
index 0fd3197..51892d9 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostConfigRecoveryHandler.java
@@ -20,12 +20,13 @@
 */
 package org.apache.qpid.server.virtualhost;
 
+import org.apache.qpid.server.federation.BrokerLink;
+import org.apache.qpid.server.message.EnqueableMessage;
 import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
 import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.store.MessageStoreRecoveryHandler;
 import org.apache.qpid.server.store.StoredMessage;
 import org.apache.qpid.server.store.TransactionLogRecoveryHandler;
-import org.apache.qpid.server.store.TransactionLog;
 import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.server.queue.AMQQueue;
 import org.apache.qpid.server.queue.AMQQueueFactory;
@@ -43,7 +44,7 @@
 import org.apache.qpid.AMQException;
 
 import org.apache.log4j.Logger;
-import org.apache.qpid.server.util.ByteBufferInputStream;
+import org.apache.qpid.util.ByteBufferInputStream;
 
 import java.io.DataInputStream;
 import java.io.IOException;
@@ -54,11 +55,13 @@
 import java.util.Map;
 import java.util.HashMap;
 import java.util.TreeMap;
+import java.util.UUID;
 
 public class VirtualHostConfigRecoveryHandler implements ConfigurationRecoveryHandler,
                                                         ConfigurationRecoveryHandler.QueueRecoveryHandler,
                                                         ConfigurationRecoveryHandler.ExchangeRecoveryHandler,
                                                         ConfigurationRecoveryHandler.BindingRecoveryHandler,
+                                                        ConfigurationRecoveryHandler.BrokerLinkRecoveryHandler,
                                                         MessageStoreRecoveryHandler,
                                                         MessageStoreRecoveryHandler.StoredMessageRecoveryHandler,
                                                         TransactionLogRecoveryHandler,
@@ -73,7 +76,6 @@
     private List<ProcessAction> _actions;
 
     private MessageStore _store;
-    private TransactionLog _transactionLog;
 
     private final Map<String, Integer> _queueRecoveries = new TreeMap<String, Integer>();
     private Map<Long, ServerMessage> _recoveredMessages = new HashMap<Long, ServerMessage>();
@@ -86,7 +88,7 @@
         _virtualHost = virtualHost;
     }
 
-    public QueueRecoveryHandler begin(MessageStore store)
+    public VirtualHostConfigRecoveryHandler begin(MessageStore store)
     {
         _logSubject = new MessageStoreLogSubject(_virtualHost,store);
         _store = store;
@@ -99,14 +101,12 @@
     {
         try
         {
-            AMQShortString queueNameShortString = new AMQShortString(queueName);
-    
-            AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueNameShortString);
+            AMQQueue q = _virtualHost.getQueueRegistry().getQueue(queueName);
     
             if (q == null)
             {
-                q = AMQQueueFactory.createAMQQueueImpl(queueNameShortString, true, owner == null ? null : new AMQShortString(owner), false, exclusive, _virtualHost,
-                                                       arguments);
+                q = AMQQueueFactory.createAMQQueueImpl(queueName, true, owner, false, exclusive, _virtualHost,
+                                                       FieldTable.convertToMap(arguments));
                 _virtualHost.getQueueRegistry().registerQueue(q);
             }
     
@@ -183,13 +183,19 @@
     public void completeMessageRecovery()
     {
         //TODO - log end
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
-    public TransactionLogRecoveryHandler.QueueEntryRecoveryHandler begin(TransactionLog log)
+    public BridgeRecoveryHandler brokerLink(final UUID id,
+                                            final long createTime,
+                                            final Map<String, String> arguments)
     {
-        _transactionLog = log;
-        return this;
+        BrokerLink blink = _virtualHost.createBrokerConnection(id, createTime, arguments);
+        return new BridgeRecoveryHandlerImpl(blink);
+        
+    }
+
+    public void completeBrokerLinkRecovery()
+    {
     }
 
     private static final class ProcessAction
@@ -270,9 +276,9 @@
 
     }
 
-    public void completeBindingRecovery()
+    public BrokerLinkRecoveryHandler completeBindingRecovery()
     {
-        //return this;
+        return this;
     }
 
     public void complete()
@@ -316,15 +322,15 @@
                 else
                 {
                     _logger.warn("Message id " + messageId + " referenced in log as enqueued in queue " + queue.getNameShortString() + " is unknown, entry will be discarded");
-                    TransactionLog.Transaction txn = _transactionLog.newTransaction();
-                    txn.dequeueMessage(queue, messageId);
+                    MessageStore.Transaction txn = _store.newTransaction();
+                    txn.dequeueMessage(queue, new DummyMessage(messageId));
                     txn.commitTranAsync();
                 }
             }
             else
             {
                 _logger.warn("Message id " + messageId + " in log references queue " + queueName + " which is not in the configuration, entry will be discarded");
-                TransactionLog.Transaction txn = _transactionLog.newTransaction();
+                MessageStore.Transaction txn = _store.newTransaction();
                 TransactionLogResource mockQueue =
                         new TransactionLogResource()
                         {
@@ -334,7 +340,7 @@
                                 return queueName;
                             }
                         };
-                txn.dequeueMessage(mockQueue, messageId);
+                txn.dequeueMessage(mockQueue, new DummyMessage(messageId));
                 txn.commitTranAsync();
             }
 
@@ -367,4 +373,51 @@
         CurrentActor.get().message(_logSubject, TransactionLogMessages.RECOVERY_COMPLETE(null, false));
     }
 
+    private static class DummyMessage implements EnqueableMessage
+    {
+
+
+        private final long _messageId;
+
+        public DummyMessage(long messageId)
+        {
+            _messageId = messageId;
+        }
+
+        public long getMessageNumber()
+        {
+            return _messageId;
+        }
+
+
+        public boolean isPersistent()
+        {
+            return true;
+        }
+
+
+        public StoredMessage getStoredMessage()
+        {
+            return null;
+        }
+    }
+
+    private class BridgeRecoveryHandlerImpl implements BridgeRecoveryHandler
+    {
+        private final BrokerLink _blink;
+
+        public BridgeRecoveryHandlerImpl(final BrokerLink blink)
+        {
+            _blink = blink;
+        }
+
+        public void bridge(final UUID id, final long createTime, final Map<String, String> arguments)
+        {
+            _blink.createBridge(id, createTime, arguments);
+        }
+
+        public void completeBridgeRecoveryForLink()
+        {
+        }
+    }
 }
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
index fde7582..a4a3633 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostImpl.java
@@ -55,6 +55,7 @@
 import org.apache.qpid.server.exchange.Exchange;
 import org.apache.qpid.server.exchange.ExchangeFactory;
 import org.apache.qpid.server.exchange.ExchangeRegistry;
+import org.apache.qpid.server.federation.Bridge;
 import org.apache.qpid.server.federation.BrokerLink;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.actors.CurrentActor;
@@ -77,7 +78,6 @@
 import org.apache.qpid.server.store.ConfigurationRecoveryHandler;
 import org.apache.qpid.server.store.DurableConfigurationStore;
 import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.TransactionLog;
 import org.apache.qpid.server.virtualhost.plugins.VirtualHostPlugin;
 import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory;
 
@@ -231,7 +231,10 @@
         if (store != null)
         {
             _messageStore = store;
-            _durableConfigurationStore = store;
+            if(store instanceof DurableConfigurationStore)
+            {
+                _durableConfigurationStore = (DurableConfigurationStore) store;
+            }
         }
         else
         {
@@ -383,6 +386,8 @@
         Class clazz = Class.forName(messageStoreClass);
         Object o = clazz.newInstance();
 
+
+
         if (!(o instanceof MessageStore))
         {
             throw new ClassCastException("Message store class must implement " + MessageStore.class + ". Class " + clazz +
@@ -393,10 +398,18 @@
 
         MessageStoreLogSubject storeLogSubject = new MessageStoreLogSubject(this, messageStore);
 
-        messageStore.configureConfigStore(this.getName(),
-                                          recoveryHandler,
-                                          hostConfig.getStoreConfiguration(),
-                                          storeLogSubject);
+
+        if(messageStore instanceof DurableConfigurationStore)
+        {
+            DurableConfigurationStore durableConfigurationStore = (DurableConfigurationStore) messageStore;
+
+            durableConfigurationStore.configureConfigStore(this.getName(),
+                                              recoveryHandler,
+                                              hostConfig.getStoreConfiguration(),
+                                              storeLogSubject);
+
+            _durableConfigurationStore = durableConfigurationStore;
+        }
 
         messageStore.configureMessageStore(this.getName(),
                                            recoveryHandler,
@@ -408,7 +421,8 @@
                                            storeLogSubject);
 
         _messageStore = messageStore;
-        _durableConfigurationStore = messageStore;
+
+
     }
 
     private void initialiseModel(VirtualHostConfiguration config) throws ConfigurationException, AMQException
@@ -556,11 +570,6 @@
         return _messageStore;
     }
 
-    public TransactionLog getTransactionLog()
-    {
-        return _messageStore;
-    }
-
     public DurableConfigurationStore getDurableConfigurationStore()
     {
         return _durableConfigurationStore;
@@ -725,6 +734,16 @@
         _statisticsEnabled = enabled;
     }
 
+    public BrokerLink createBrokerConnection(UUID id, long createTime, Map<String,String> arguments)
+    {
+        BrokerLink blink = new BrokerLink(this, id, createTime, arguments);
+        // TODO - cope with duplicate broker link creation requests
+        _links.putIfAbsent(blink,blink);
+        getConfigStore().addConfiguredObject(blink);
+        return blink;
+    }
+
+    
     public void createBrokerConnection(final String transport,
                                        final String host,
                                        final int port,
@@ -735,10 +754,11 @@
                                        final String password)
     {
         BrokerLink blink = new BrokerLink(this, transport, host, port, vhost, durable, authMechanism, username, password);
-        if(_links.putIfAbsent(blink,blink) != null)
-        {
-            getConfigStore().addConfiguredObject(blink);
-        }
+
+        // TODO - cope with duplicate broker link creation requests
+        _links.putIfAbsent(blink,blink);
+        getConfigStore().addConfiguredObject(blink);
+
     }
 
     public void removeBrokerConnection(final String transport,
@@ -788,7 +808,9 @@
         public List<Exchange> exchange = new LinkedList<Exchange>();
         public List<CreateQueueTuple> queue = new LinkedList<CreateQueueTuple>();
         public List<CreateBindingTuple> bindings = new LinkedList<CreateBindingTuple>();
-
+        public List<BrokerLink> links = new LinkedList<BrokerLink>();
+        public List<Bridge> bridges = new LinkedList<Bridge>();
+        
         public void configure(VirtualHost virtualHost, String base, VirtualHostConfiguration config) throws Exception
         {
         }
@@ -883,6 +905,30 @@
         public void updateQueue(AMQQueue queue) throws AMQStoreException
         {
         }
+
+        public void createBrokerLink(final BrokerLink link) throws AMQStoreException
+        {
+            if(link.isDurable())
+            {
+                links.add(link);
+            }
+        }
+
+        public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException
+        {
+        }
+
+        public void createBridge(final Bridge bridge) throws AMQStoreException
+        {
+            if(bridge.isDurable())
+            {
+                bridges.add(bridge);
+            }
+        }
+
+        public void deleteBridge(final Bridge bridge) throws AMQStoreException
+        {
+        }
     }
 
     @Override
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
index bfcdbe7..3d3c7b6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/tools/security/Passwd.java
@@ -20,15 +20,13 @@
  */
 package org.apache.qpid.tools.security;
 
-import org.apache.commons.codec.binary.Base64;
-
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.security.DigestException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
-import java.security.DigestException;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintStream;
+import org.apache.commons.codec.binary.Base64;
 
 public class Passwd
 {
@@ -40,7 +38,14 @@
             System.exit(0);
         }
 
-        byte[] data = args[1].getBytes("utf-8");
+        Passwd passwd = new Passwd();
+        String output = passwd.getOutput(args[0], args[1]);
+        System.out.println(output);
+    }
+
+    public String getOutput(String userName, String password) throws UnsupportedEncodingException, NoSuchAlgorithmException
+    {
+        byte[] data = password.getBytes("utf-8");
 
         MessageDigest md = MessageDigest.getInstance("MD5");
 
@@ -55,24 +60,8 @@
 
         byte[] encoded = b64.encode(digest);
 
-        output(args[0], encoded);
+        String encodedStr = new String(encoded, Charset.forName("utf-8"));
+        return userName + ":" + encodedStr;
     }
 
-    private static void output(String user, byte[] encoded) throws IOException
-    {
-        PrintStream ps = new PrintStream(System.out);
-
-        user += ":";
-        ps.write(user.getBytes("utf-8"));
-
-        for (byte b : encoded)
-        {
-            ps.write(b);
-        }
-
-        ps.println();
-
-        ps.flush();
-        ps.close();
-    }
 }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java
index eea8e17..3e4c302 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/MainTest.java
@@ -165,6 +165,11 @@
             _options = options;
         }
 
+        @Override
+        protected void setExceptionHandler()
+        {
+        }
+
         public BrokerOptions getOptions()
         {
             return _options;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
index 7739f99..eb4a90d 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/ServerConfigurationTest.java
@@ -600,19 +600,6 @@
         assertEquals("a", _serverConfig.getConnectorCertType());
     }
 
-    public void testGetUseBiasedWrites() throws ConfigurationException
-    {
-        // Check default
-        _serverConfig.initialise();
-        assertEquals(false, _serverConfig.getUseBiasedWrites());
-
-        // Check value we set
-        _config.setProperty("advanced.useWriteBiasedPool", true);
-        _serverConfig = new ServerConfiguration(_config);
-        _serverConfig.initialise();
-        assertEquals(true, _serverConfig.getUseBiasedWrites());
-    }
-
     public void testGetHousekeepingCheckPeriod() throws ConfigurationException
     {
         // Check default
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
index a0a29cf..7bd711a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/exchange/AbstractHeadersExchangeTestBase.java
@@ -72,7 +72,7 @@
     /**
      * Not used in this test, just there to stub out the routing calls
      */
-    private MessageStore _store = new MemoryMessageStore();
+    private MemoryMessageStore _store = new MemoryMessageStore();
 
 
     BindingFactory bindingFactory = new BindingFactory(new DurableConfigurationStore.Source()
@@ -310,7 +310,7 @@
          * @throws AMQException
          */
         @Override
-        public void enqueue(ServerMessage msg, PostEnqueueAction action) throws AMQException
+        public void enqueue(ServerMessage msg, boolean sync, PostEnqueueAction action) throws AMQException
         {
             messages.add( new HeadersExchangeTest.Message((AMQMessage) msg));
             final QueueEntry queueEntry = new QueueEntry()
@@ -318,47 +318,47 @@
 
                 public AMQQueue getQueue()
                 {
-                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                    return null;
                 }
 
                 public AMQMessage getMessage()
                 {
-                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                    return null;
                 }
 
                 public long getSize()
                 {
-                    return 0;  //To change body of implemented methods use File | Settings | File Templates.
+                    return 0;
                 }
 
                 public boolean getDeliveredToConsumer()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean expired() throws AMQException
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean isAvailable()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean isAcquired()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean acquire()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean acquire(Subscription sub)
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean delete()
@@ -373,17 +373,17 @@
 
                 public boolean acquiredBySubscription()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean isAcquiredBy(Subscription subscription)
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public void release()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public boolean releaseButRetain()
@@ -393,42 +393,42 @@
 
                 public boolean immediateAndNotDelivered()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public void setRedelivered()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public AMQMessageHeader getMessageHeader()
                 {
-                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                    return null;
                 }
 
                 public boolean isPersistent()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public boolean isRedelivered()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public Subscription getDeliveredSubscription()
                 {
-                    return null;  //To change body of implemented methods use File | Settings | File Templates.
+                    return null;
                 }
 
                 public void reject()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public boolean isRejectedBy(long subscriptionId)
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public void requeue(Subscription subscription)
@@ -438,42 +438,42 @@
 
                 public void dequeue()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public void dispose()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public void discard()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public void routeToAlternate()
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public boolean isQueueDeleted()
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public void addStateChangeListener(StateChangeListener listener)
                 {
-                    //To change body of implemented methods use File | Settings | File Templates.
+                  
                 }
 
                 public boolean removeStateChangeListener(StateChangeListener listener)
                 {
-                    return false;  //To change body of implemented methods use File | Settings | File Templates.
+                    return false;
                 }
 
                 public int compareTo(final QueueEntry o)
                 {
-                    return 0;  //To change body of implemented methods use File | Settings | File Templates.
+                    return 0;
                 }
 
                 public boolean isDequeued()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java
index 32ad1d1..9a065ea 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/CurrentActorTest.java
@@ -23,6 +23,7 @@
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.qpid.AMQException;
 import org.apache.qpid.server.AMQChannel;
+import org.apache.qpid.server.logging.LogActor;
 import org.apache.qpid.server.logging.NullRootMessageLogger;
 
 /**
@@ -49,10 +50,7 @@
 public class CurrentActorTest extends BaseConnectionActorTestCase
 {
     //Set this to be a reasonably large number
-    int THREADS = 10;
-
-    // Record any exceptions that are thrown by the threads
-    Exception[] _errors = new Exception[THREADS];
+    private static final int THREADS = 10;
 
     /**
      * Test that CurrentActor behaves as LIFO queue.
@@ -161,19 +159,11 @@
     public void testThreadLocal()
     {
 
-        new Runnable(){
-            public void run()
-            {
-                System.out.println(_errors[0]);
-            }
-        };
-
         // Setup the threads
-        Thread[] threads = new Thread[THREADS];
+        LogMessagesWithAConnectionActor[] threads = new LogMessagesWithAConnectionActor[THREADS];
         for (int count = 0; count < THREADS; count++)
         {
-            Runnable test = new LogMessagesWithAConnectionActor(count);
-            threads[count] = new Thread(test);
+            threads[count] = new LogMessagesWithAConnectionActor();
         }
 
         //Run the threads
@@ -198,10 +188,10 @@
         // Verify that none of the tests threw an exception
         for (int count = 0; count < THREADS; count++)
         {
-            if (_errors[count] != null)
+            if (threads[count].getException() != null)
             {
-                _errors[count].printStackTrace();
-                fail("Error occured in thread:" + count);
+                threads[count].getException().printStackTrace();
+                fail("Error occured in thread:" + count + "("+threads[count].getException()+")");
             }
         }
     }
@@ -210,13 +200,12 @@
      * Creates a new ConnectionActor and logs the given number of messages
      * before removing the actor and validating that there is no set actor.
      */
-    public class LogMessagesWithAConnectionActor implements Runnable
+    public class LogMessagesWithAConnectionActor extends Thread
     {
-        int count;
+        Throwable _exception;
 
-        LogMessagesWithAConnectionActor(int count)
+        public LogMessagesWithAConnectionActor()
         {
-            this.count = count;
         }
 
         public void run()
@@ -227,6 +216,7 @@
             //fixme reminder that we need a better approach for broker testing.
             try
             {
+                LogActor defaultActor = CurrentActor.get();
 
                 AMQPConnectionActor actor = new AMQPConnectionActor(getSession(),
                                                                     new NullRootMessageLogger());
@@ -237,20 +227,26 @@
                 sendTestLogMessage(CurrentActor.get());
 
                 // Verify it was the same actor as we set earlier
-                assertEquals("Retrieved actor is not as expected ",
-                             actor, CurrentActor.get());
+                if(!actor.equals(CurrentActor.get()))
+                   throw new IllegalArgumentException("Retrieved actor is not as expected ");
 
                 // Verify that removing the actor works for this thread
                 CurrentActor.remove();
 
-                assertNull("CurrentActor should be null", CurrentActor.get());
+                if(CurrentActor.get() != defaultActor)
+                   throw new IllegalArgumentException("CurrentActor ("+CurrentActor.get()+") should be default actor" + defaultActor);
             }
-            catch (Exception e)
+            catch (Throwable e)
             {
-                _errors[count] = e;
+                _exception = e;
             }
 
         }
+
+        public Throwable getException()
+        {
+            return _exception;
+        }
     }
 
 }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
index 2ce4305..d5f8ef3 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/AMQPriorityQueueTest.java
@@ -64,17 +64,17 @@
         ArrayList<QueueEntry> msgs = _subscription.getMessages();
         try
         {
-            assertEquals(new Long(1L), msgs.get(0).getMessage().getMessageNumber());
-            assertEquals(new Long(6L), msgs.get(1).getMessage().getMessageNumber());
-            assertEquals(new Long(8L), msgs.get(2).getMessage().getMessageNumber());
+            assertEquals(1L, msgs.get(0).getMessage().getMessageNumber());
+            assertEquals(6L, msgs.get(1).getMessage().getMessageNumber());
+            assertEquals(8L, msgs.get(2).getMessage().getMessageNumber());
 
-            assertEquals(new Long(2L), msgs.get(3).getMessage().getMessageNumber());
-            assertEquals(new Long(5L), msgs.get(4).getMessage().getMessageNumber());
-            assertEquals(new Long(7L), msgs.get(5).getMessage().getMessageNumber());
+            assertEquals(2L, msgs.get(3).getMessage().getMessageNumber());
+            assertEquals(5L, msgs.get(4).getMessage().getMessageNumber());
+            assertEquals(7L, msgs.get(5).getMessage().getMessageNumber());
 
-            assertEquals(new Long(3L), msgs.get(6).getMessage().getMessageNumber());
-            assertEquals(new Long(4L), msgs.get(7).getMessage().getMessageNumber());
-            assertEquals(new Long(9L), msgs.get(8).getMessage().getMessageNumber());
+            assertEquals(3L, msgs.get(6).getMessage().getMessageNumber());
+            assertEquals(4L, msgs.get(7).getMessage().getMessageNumber());
+            assertEquals(9L, msgs.get(8).getMessage().getMessageNumber());
         }
         catch (AssertionFailedError afe)
         {
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
index 0daf791..f97ac56 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockAMQQueue.java
@@ -30,7 +30,6 @@
 import org.apache.qpid.server.management.ManagedObject;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.security.AuthorizationHolder;
-import org.apache.qpid.server.AMQChannel;
 import org.apache.qpid.server.protocol.AMQSessionModel;
 import org.apache.qpid.server.binding.Binding;
 import org.apache.qpid.server.txn.ServerTransaction;
@@ -168,22 +167,22 @@
 
     public UUID getId()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public QueueConfigType getConfigType()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public ConfiguredObject getParent()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public boolean isDurable()
     {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        return false;
     }
 
     public boolean isAutoDelete()
@@ -199,7 +198,7 @@
 
     public AMQShortString getOwner()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public void setVirtualHost(VirtualHost virtualhost)
@@ -219,22 +218,22 @@
 
     public void registerSubscription(Subscription subscription, boolean exclusive) throws AMQException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void unregisterSubscription(Subscription subscription) throws AMQException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public int getConsumerCount()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public int getActiveConsumerCount()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public boolean hasExclusiveSubscriber()
@@ -244,37 +243,37 @@
 
     public boolean isUnused()
     {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        return false;
     }
 
     public boolean isEmpty()
     {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        return false;
     }
 
     public int getMessageCount()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public int getUndeliveredMessageCount()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public long getQueueDepth()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public long getReceivedMessageCount()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public long getOldestMessageArrivalTime()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public boolean isDeleted()
@@ -297,59 +296,58 @@
     }
 
 
+    public void enqueue(ServerMessage message, boolean sync, PostEnqueueAction action) throws AMQException
+    {
+    }
+
     public void requeue(QueueEntry entry)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public void requeue(QueueEntryImpl storeContext, Subscription subscription)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public void dequeue(QueueEntry entry, Subscription sub)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public boolean resend(QueueEntry entry, Subscription subscription) throws AMQException
     {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        return false;
     }
 
     public void addQueueDeleteTask(Task task)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public void removeQueueDeleteTask(final Task task)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public List<QueueEntry> getMessagesOnTheQueue()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public List<QueueEntry> getMessagesOnTheQueue(long fromMessageId, long toMessageId)
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public List<Long> getMessagesOnTheQueue(int num)
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public List<Long> getMessagesOnTheQueue(int num, int offest)
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public QueueEntry getMessageOnTheQueue(long messageId)
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public List<QueueEntry> getMessagesRangeOnTheQueue(long fromPosition, long toPosition)
@@ -359,146 +357,137 @@
 
     public void moveMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction storeContext)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void copyMessagesToAnotherQueue(long fromMessageId, long toMessageId, String queueName, ServerTransaction storeContext)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void removeMessagesFromQueue(long fromMessageId, long toMessageId)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public long getMaximumMessageSize()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setMaximumMessageSize(long value)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public long getMaximumMessageCount()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setMaximumMessageCount(long value)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public long getMaximumQueueDepth()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setMaximumQueueDepth(long value)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public long getMaximumMessageAge()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setMaximumMessageAge(long maximumMessageAge)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
-    }
-
-    public boolean getBlockOnQueueFull()
-    {
-        return false;
-    }
-
-    public void setBlockOnQueueFull(boolean block)
-    {
+      
     }
 
     public long getMinimumAlertRepeatGap()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void deleteMessageFromTop()
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public long clearQueue()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
 
     public void checkMessageStatus() throws AMQException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public Set<NotificationCheck> getNotificationChecks()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public void flushSubscription(Subscription sub) throws AMQException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void deliverAsync(Subscription sub)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void deliverAsync()
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void stop()
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public boolean isExclusive()
     {
-        return false;  //To change body of implemented methods use File | Settings | File Templates.
+        return false;
     }
 
     public Exchange getAlternateExchange()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public void setAlternateExchange(Exchange exchange)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public Map<String, Object> getArguments()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
-    public void checkCapacity(AMQChannel channel)
+    public void checkCapacity(AMQSessionModel channel)
     {
     }
 
     public ManagedObject getManagedObject()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public int compareTo(AMQQueue o)
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setMinimumAlertRepeatGap(long value)
@@ -508,22 +497,22 @@
 
     public long getCapacity()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setCapacity(long capacity)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public long getFlowResumeCapacity()
     {
-        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+        return 0;
     }
 
     public void setFlowResumeCapacity(long flowResumeCapacity)
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+      
     }
 
     public void configure(ConfigurationPlugin config)
@@ -533,7 +522,7 @@
 
     public ConfigurationPlugin getConfiguration()
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
     public AuthorizationHolder getAuthorizationHolder()
@@ -612,20 +601,20 @@
 
     }
 
-    @Override
     public int getMaximumDeliveryCount()
     {
         return 0;
     }
 
-    @Override
     public void setMaximumDeliveryCount(int maximumDeliveryCount)
     {
     }
 
-    @Override
     public void setAlternateExchange(String exchangeName)
     {
     }
 
+    public void visit(final Visitor visitor)
+    {
+    }
 }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
index e2418a8..b4f8c6d 100755
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/MockStoredMessage.java
@@ -23,7 +23,6 @@
 import org.apache.qpid.framing.FieldTable;
 
 import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.TransactionLog;
 import org.apache.qpid.server.store.StoredMessage;
 import org.apache.qpid.server.message.MessageMetaData;
 import org.apache.qpid.framing.ContentHeaderBody;
@@ -107,7 +106,17 @@
         return src.limit();
     }
 
-    public TransactionLog.StoreFuture flushToStore()
+
+
+    public ByteBuffer getContent(int offsetInMessage, int size)
+    {
+        ByteBuffer buf = ByteBuffer.allocate(size);
+        getContent(offsetInMessage, buf);
+        buf.position(0);
+        return  buf;
+    }
+
+    public MessageStore.StoreFuture flushToStore()
     {
         return MessageStore.IMMEDIATE_FUTURE;
     }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java
index 7a3f6f7..cf91020 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/QueueEntryListTestBase.java
@@ -164,7 +164,7 @@
         final QueueEntry head = getTestList().getHead();
         assertNull("Head entry should not contain an actual message", head.getMessage());
         assertEquals("Unexpected message id for first list entry", getExpectedFirstMsgId(), getTestList().next(head)
-                        .getMessage().getMessageNumber().longValue());
+                        .getMessage().getMessageNumber());
     }
 
     /**
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
index 6c7094c..28d52f4 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleAMQQueueTest.java
@@ -649,9 +649,7 @@
                                         public void onRollback()
                                         {
                                         }
-                                    });
-
-
+                                    }, 0L);
 
         // Check that it is enqueued
         AMQQueue data = _store.getMessages().get(1L);
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
index f3ba6a5..a873739 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryListTest.java
@@ -162,8 +162,8 @@
         while (entry != null)
         {           
             assertFalse("Entry " + entry.getMessage().getMessageNumber() + " should not have been deleted", entry.isDeleted());
-            assertNotNull("QueueEntry was not found in the list of remaining entries", 
-                    remainingMessages.get(entry.getMessage().getMessageNumber().intValue()));
+            assertNotNull("QueueEntry "+entry.getMessage().getMessageNumber()+" was not found in the list of remaining entries " + remainingMessages,
+                    remainingMessages.get((int)(entry.getMessage().getMessageNumber())));
 
             count++;
             entry = entry.getNextNode();
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java
index eca8456..34ad0e5 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/queue/SortedQueueEntryListTest.java
@@ -317,7 +317,7 @@
         assertEquals("Sorted queue entry value is not as expected",
                         expectedSortKey, entry.getMessage().getMessageHeader().getHeader("KEY"));
         assertEquals("Sorted queue entry id is not as expected",
-                        Long.valueOf(expectedMessageId), entry.getMessage().getMessageNumber());
+                        expectedMessageId, entry.getMessage().getMessageNumber());
     }
 
 }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
index 1d0a9d6..90adaa1 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/MessageStoreTest.java
@@ -558,7 +558,7 @@
     /**
      * Delete the Store Environment path
      *
-     * @param configuration The configuration that contains the store environment path.
+     * @param environmentPath The configuration that contains the store environment path.
      */
     private void cleanup(File environmentPath)
     {
@@ -636,7 +636,7 @@
                 {
                     //To change body of implemented methods use File | Settings | File Templates.
                 }
-            });
+            }, 0L);
         }
     }
 
@@ -710,7 +710,7 @@
 
             if (queue.isDurable() && !queue.isAutoDelete())
             {
-                getVirtualHost().getMessageStore().createQueue(queue, queueArguments);
+                getVirtualHost().getDurableConfigurationStore().createQueue(queue, queueArguments);
             }
         }
         catch (AMQException e)
@@ -754,7 +754,7 @@
             getVirtualHost().getExchangeRegistry().registerExchange(exchange);
             if (durable)
             {
-                getVirtualHost().getMessageStore().createExchange(exchange);
+                getVirtualHost().getDurableConfigurationStore().createExchange(exchange);
             }
         }
         catch (AMQException e)
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
index 5ff8455..44006df 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/SkeletonMessageStore.java
@@ -26,6 +26,7 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.framing.abstraction.ContentChunk;
+import org.apache.qpid.server.message.EnqueableMessage;
 import org.apache.qpid.server.message.MessageMetaData;
 import org.apache.qpid.server.queue.AMQQueue;
 import org.apache.qpid.server.exchange.Exchange;
@@ -42,18 +43,11 @@
  */
 public class SkeletonMessageStore implements MessageStore
 {
-    private final AtomicLong _messageId = new AtomicLong(1);
-
-    public void configure(String base, Configuration config) throws Exception
-    {
-    }
-
     public void configureConfigStore(String name,
                           ConfigurationRecoveryHandler recoveryHandler,
                           Configuration config,
                           LogSubject logSubject) throws Exception
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public void configureMessageStore(String name,
@@ -61,7 +55,6 @@
                                       Configuration config,
                                       LogSubject logSubject) throws Exception
     {
-        //To change body of implemented methods use File | Settings | File Templates.
     }
 
     public void close() throws Exception
@@ -70,31 +63,28 @@
 
     public <M extends StorableMessageMetaData> StoredMessage<M> addMessage(M metaData)
     {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
+        return null;
     }
 
-    public void removeMessage(Long messageId)
-    {
-    }
 
     public void createExchange(Exchange exchange) throws AMQStoreException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+
     }
 
     public void removeExchange(Exchange exchange) throws AMQStoreException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+
     }
 
     public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+
     }
 
     public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+
     }
 
     public void createQueue(AMQQueue queue) throws AMQStoreException
@@ -105,63 +95,11 @@
     {
     }
 
-
-
-
-    public List<AMQQueue> createQueues() throws AMQException
-    {
-        return null;
-    }
-
-    public Long getNewMessageId()
-    {
-        return _messageId.getAndIncrement();
-    }
-
-    public void storeContentBodyChunk(
-            Long messageId,
-            int index,
-            ContentChunk contentBody,
-            boolean lastContentBody) throws AMQException
-    {
-
-    }
-
-    public void storeMessageMetaData(Long messageId, MessageMetaData messageMetaData) throws AMQException
-    {
-
-    }
-
-    public MessageMetaData getMessageMetaData(Long messageId) throws AMQException
-    {
-        return null;
-    }
-
-    public ContentChunk getContentBodyChunk(Long messageId, int index) throws AMQException
-    {
-        return null;
-    }
-
     public boolean isPersistent()
     {
         return false;
     }
 
-    public void storeMessageHeader(Long messageNumber, ServerMessage message)
-    {
-        //To change body of implemented methods use File | Settings | File Templates.
-    }
-
-    public void storeContent(Long messageNumber, long offset, ByteBuffer body)
-    {
-        //To change body of implemented methods use File | Settings | File Templates.
-    }
-
-    public ServerMessage getMessage(Long messageNumber)
-    {
-        return null;  //To change body of implemented methods use File | Settings | File Templates.
-    }
-
     public void removeQueue(final AMQQueue queue) throws AMQStoreException
     {
 
@@ -172,7 +110,7 @@
                                         Configuration storeConfiguration,
                                         LogSubject logSubject) throws Exception
     {
-        //To change body of implemented methods use File | Settings | File Templates.
+
     }
 
     public Transaction newTransaction()
@@ -180,19 +118,19 @@
         return new Transaction()
         {
 
-            public void enqueueMessage(TransactionLogResource  queue, Long messageId) throws AMQStoreException
+            public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
             {
-                //To change body of implemented methods use File | Settings | File Templates.
+
             }
 
-            public void dequeueMessage(TransactionLogResource  queue, Long messageId) throws AMQStoreException
+            public void dequeueMessage(TransactionLogResource  queue, EnqueableMessage message) throws AMQStoreException
             {
-                //To change body of implemented methods use File | Settings | File Templates.
+
             }
 
             public void commitTran() throws AMQStoreException
             {
-                //To change body of implemented methods use File | Settings | File Templates.
+
             }
 
             public StoreFuture commitTranAsync() throws AMQStoreException
@@ -213,7 +151,7 @@
 
             public void abortTran() throws AMQStoreException
             {
-                //To change body of implemented methods use File | Settings | File Templates.
+
             }
         };
     }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
index 4dea13d..fa698f4 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestMemoryMessageStore.java
@@ -82,6 +82,12 @@
             return _storedMessage.getContent(offsetInMessage, dst);
         }
 
+
+        public ByteBuffer getContent(int offsetInMessage, int size)
+        {
+            return _storedMessage.getContent(offsetInMessage, size);
+        }
+
         public StoreFuture flushToStore()
         {
             return _storedMessage.flushToStore();
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
index 3593297..3804d0d 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/store/TestableMemoryMessageStore.java
@@ -25,6 +25,8 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.qpid.AMQStoreException;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.queue.AMQQueue;
 
 /**
@@ -66,14 +68,14 @@
 
     private class TestableTransaction implements Transaction
     {
-        public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+        public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
         {
-            getMessages().put(messageId, (AMQQueue)queue);
+            getMessages().put(message.getMessageNumber(), (AMQQueue)queue);
         }
 
-        public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+        public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
         {
-            getMessages().remove(messageId);
+            getMessages().remove(message.getMessageNumber());
         }
 
         public void commitTran() throws AMQStoreException
@@ -143,6 +145,12 @@
             return _storedMessage.getContent(offsetInMessage, dst);
         }
 
+
+        public ByteBuffer getContent(int offsetInMessage, int size)
+        {
+            return _storedMessage.getContent(offsetInMessage, size);
+        }
+
         public StoreFuture flushToStore()
         {
             return _storedMessage.flushToStore();
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java
index 9afed49..98484db 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/AutoCommitTransactionTest.java
@@ -29,7 +29,7 @@
 import org.apache.qpid.server.queue.MockAMQQueue;
 import org.apache.qpid.server.queue.MockQueueEntry;
 import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState;
 import org.apache.qpid.test.utils.QpidTestCase;
 
@@ -44,7 +44,7 @@
 {
     private ServerTransaction _transaction = null;  // Class under test
     
-    private TransactionLog _transactionLog;
+    private MessageStore _transactionLog;
     private AMQQueue _queue;
     private List<AMQQueue> _queues;
     private Collection<QueueEntry> _queueEntries;
@@ -137,7 +137,7 @@
         _message = createTestMessage(false);
         _queues = createTestBaseQueues(new boolean[] {false, false, false});
         
-        _transaction.enqueue(_queues, _message, _action);
+        _transaction.enqueue(_queues, _message, _action, 0L);
 
         assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
         assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
@@ -157,7 +157,7 @@
         _message = createTestMessage(true);
         _queues = createTestBaseQueues(new boolean[] {false, false, false});
         
-        _transaction.enqueue(_queues, _message, _action);
+        _transaction.enqueue(_queues, _message, _action, 0L);
 
         assertEquals("Enqueue of persistent message to non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
         assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
@@ -175,7 +175,7 @@
         _message = createTestMessage(true);
         _queues = createTestBaseQueues(new boolean[] {false, true, false, true});
         
-        _transaction.enqueue(_queues, _message, _action);
+        _transaction.enqueue(_queues, _message, _action, 0L);
 
         assertEquals("Enqueue of persistent message to durable/non-durable queues must cause messages to be enqueued", 2, _storeTransaction.getNumberOfEnqueuedMessages());
         assertEquals("Unexpected transaction state", TransactionState.COMMITTED, _storeTransaction.getState());
@@ -198,7 +198,7 @@
         
         try
         {
-            _transaction.enqueue(_queues, _message, _action);
+            _transaction.enqueue(_queues, _message, _action, 0L);
             fail("Exception not thrown");
         }
         catch (RuntimeException re)
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java
index e81fd8e..484beb8 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/LocalTransactionTest.java
@@ -29,7 +29,7 @@
 import org.apache.qpid.server.queue.MockAMQQueue;
 import org.apache.qpid.server.queue.MockQueueEntry;
 import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.server.store.TransactionLog;
+import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.txn.MockStoreTransaction.TransactionState;
 import org.apache.qpid.test.utils.QpidTestCase;
 
@@ -51,7 +51,7 @@
     private MockAction _action1;
     private MockAction _action2;
     private MockStoreTransaction _storeTransaction;
-    private TransactionLog _transactionLog;
+    private MessageStore _transactionLog;
 
 
     @Override
@@ -140,7 +140,7 @@
         _message = createTestMessage(false);
         _queues = createTestBaseQueues(new boolean[] {false, false, false});
         
-        _transaction.enqueue(_queues, _message, _action1);
+        _transaction.enqueue(_queues, _message, _action1, 0L);
 
         assertEquals("Enqueue of non-persistent message must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
         assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
@@ -156,7 +156,7 @@
         _message = createTestMessage(true);
         _queues = createTestBaseQueues(new boolean[] {false, false, false});
         
-        _transaction.enqueue(_queues, _message, _action1);
+        _transaction.enqueue(_queues, _message, _action1, 0L);
   
         assertEquals("Enqueue of persistent message to non-durable queues must not cause message to be enqueued", 0, _storeTransaction.getNumberOfEnqueuedMessages());
         assertEquals("Unexpected transaction state", TransactionState.NOT_STARTED, _storeTransaction.getState());
@@ -173,7 +173,7 @@
         _message = createTestMessage(true);
         _queues = createTestBaseQueues(new boolean[] {false, true, false, true});
         
-        _transaction.enqueue(_queues, _message, _action1);
+        _transaction.enqueue(_queues, _message, _action1, 0L);
 
         assertEquals("Enqueue of persistent message to durable/non-durable queues must cause messages to be enqueued", 2, _storeTransaction.getNumberOfEnqueuedMessages());
         assertEquals("Unexpected transaction state", TransactionState.STARTED, _storeTransaction.getState());
@@ -196,7 +196,7 @@
         
         try
         {
-            _transaction.enqueue(_queues, _message, _action1);
+            _transaction.enqueue(_queues, _message, _action1, 0L);
             fail("Exception not thrown");
         }
         catch (RuntimeException re)
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java
index 1941feb..063023f 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockServerMessage.java
@@ -27,11 +27,12 @@
 import org.apache.qpid.server.message.AMQMessageHeader;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.store.StoredMessage;
 
 /**
  * Mock Server Message allowing its persistent flag to be controlled from test.
  */
-class MockServerMessage implements ServerMessage<MockServerMessage>
+class MockServerMessage implements ServerMessage
 {
     /**
      *
@@ -83,6 +84,11 @@
         throw new NotImplementedException();
     }
 
+    public StoredMessage getStoredMessage()
+    {
+        throw new NotImplementedException();
+    }
+
     public long getExpiration()
     {
         throw new NotImplementedException();
@@ -93,12 +99,18 @@
         throw new NotImplementedException();
     }
 
+
+    public ByteBuffer getContent(int offset, int size)
+    {
+        throw new NotImplementedException();
+    }
+
     public long getArrivalTime()
     {
         throw new NotImplementedException();
     }
 
-    public Long getMessageNumber()
+    public long getMessageNumber()
     {
         return 0L;
     }
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java
index ff37253..bf8fda3 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/txn/MockStoreTransaction.java
@@ -24,11 +24,11 @@
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.qpid.AMQStoreException;
 import org.apache.qpid.server.logging.LogSubject;
-import org.apache.qpid.server.store.TransactionLog;
-import org.apache.qpid.server.store.TransactionLogRecoveryHandler;
-import org.apache.qpid.server.store.TransactionLogResource;
-import org.apache.qpid.server.store.TransactionLog.StoreFuture;
-import org.apache.qpid.server.store.TransactionLog.Transaction;
+import org.apache.qpid.server.message.EnqueableMessage;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.store.*;
+import org.apache.qpid.server.store.MessageStore.StoreFuture;
+import org.apache.qpid.server.store.MessageStore.Transaction;
 
 /**
  * Mock implementation of a (Store) Transaction allow its state to be observed.
@@ -61,7 +61,7 @@
         return _state;
     }
 
-    public void enqueueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+    public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
     {
         if (_throwExceptionOnQueueOp)
         {
@@ -82,7 +82,7 @@
         return _numberOfEnqueuedMessages;
     }
 
-    public void dequeueMessage(TransactionLogResource queue, Long messageId) throws AMQStoreException
+    public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message) throws AMQStoreException
     {
         if (_throwExceptionOnQueueOp)
         {
@@ -107,10 +107,33 @@
         _state = TransactionState.ABORTED;
     }
 
-    public static TransactionLog createTestTransactionLog(final MockStoreTransaction storeTransaction)
+    public static MessageStore createTestTransactionLog(final MockStoreTransaction storeTransaction)
     {
-        return new TransactionLog()
+        return new MessageStore()
         {
+            public void configureMessageStore(final String name,
+                                              final MessageStoreRecoveryHandler recoveryHandler,
+                                              final Configuration config,
+                                              final LogSubject logSubject) throws Exception
+            {
+                //TODO.
+            }
+
+            public void close() throws Exception
+            {
+                //TODO.
+            }
+
+            public <T extends StorableMessageMetaData> StoredMessage<T> addMessage(final T metaData)
+            {
+                return null;  //TODO.
+            }
+
+            public boolean isPersistent()
+            {
+                return false;  //TODO.
+            }
+
             public void configureTransactionLog(String name, TransactionLogRecoveryHandler recoveryHandler,
                     Configuration storeConfiguration, LogSubject logSubject) throws Exception
             {
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java
index c043066..b2cdff8 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/virtualhost/MockVirtualHost.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.server.virtualhost;
 
+import java.util.Map;
 import java.util.UUID;
 
 import org.apache.qpid.server.binding.BindingFactory;
@@ -41,7 +42,6 @@
 import org.apache.qpid.server.stats.StatisticsCounter;
 import org.apache.qpid.server.store.DurableConfigurationStore;
 import org.apache.qpid.server.store.MessageStore;
-import org.apache.qpid.server.store.TransactionLog;
 import org.apache.qpid.server.protocol.v1_0.LinkRegistry;
 
 
@@ -66,6 +66,11 @@
 
     }
 
+    public BrokerLink createBrokerConnection(final UUID id, final long createTime, final Map<String, String> arguments)
+    {
+        return null;
+    }
+
     public IApplicationRegistry getApplicationRegistry()
     {
         return null;
@@ -161,10 +166,6 @@
         return null;
     }
 
-    public TransactionLog getTransactionLog()
-    {
-        return null;
-    }
 
     public void removeBrokerConnection(BrokerLink brokerLink)
     {
diff --git a/qpid/java/broker/src/xsl/qmf.xsl b/qpid/java/broker/src/xsl/qmf.xsl
index 3a7e10d..1e98c97 100644
--- a/qpid/java/broker/src/xsl/qmf.xsl
+++ b/qpid/java/broker/src/xsl/qmf.xsl
@@ -288,6 +288,17 @@
             <xsl:apply-templates select="node()[name()='property' or name()='statistic']" mode="optionalPropertyPresence"/>
             <xsl:apply-templates select="node()[name()='property' or name()='statistic']" mode="encodeProperty"/>
         }
+
+        public String toString()
+        {
+            return "QMF<xsl:value-of select="@name"/>GetQueryResponseCommand{id=" + getObject().getId()   
+<xsl:for-each select="node()[name()='property' or name()='statistic']">
+<xsl:if test="@type!='hilo32' and @type!='mmaTime' ">
+                + ", <xsl:value-of select="@name"/>=" + getObject().get<xsl:call-template name="initCap"><xsl:with-param name="input"><xsl:value-of select="@name"/></xsl:with-param></xsl:call-template>()
+</xsl:if>
+</xsl:for-each>
+                   + "}";
+        }
     }
     
     
@@ -530,6 +541,11 @@
             {
                 return obj.<xsl:value-of select="@name"/>( new <xsl:value-of select="$ClassName"/>ResponseCommandFactory(cmd)<xsl:if test="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">, </xsl:if><xsl:apply-templates select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]" mode="methodArgList"><xsl:with-param name="prefix">_</xsl:with-param></xsl:apply-templates> );
             }
+
+            public String toString()
+            {
+                return "<xsl:value-of select="$ClassName"/>["<xsl:for-each select="node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]"><xsl:if test="preceding-sibling::node()[name()='arg' and ( @dir='I' or @dir='IO' ) ]">+ ", "</xsl:if>+ "<xsl:value-of select="@name"/> = " + _<xsl:value-of select="@name"/> </xsl:for-each>+"]";
+            }
         }
         
         public final class <xsl:value-of select="$ClassName"/>ResponseCommandFactory
diff --git a/qpid/java/build.deps b/qpid/java/build.deps
index db28b33..c59b9eb 100644
--- a/qpid/java/build.deps
+++ b/qpid/java/build.deps
@@ -146,7 +146,7 @@
 ra.libs=${geronimo-j2ee} ${geronimo-jta} ${geronimo-jms} ${slf4j-api} ${geronimo-kernel} ${geronimo-openejb}
 
 # optional bdbstore module deps
-bdb-je=lib/bdbstore/je-4.0.117.jar
+bdb-je=lib/bdbstore/je-5.0.34.jar
 bdbstore.libs=${bdb-je}
 bdbstore.test.libs=${test.libs}
 
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
index 399534e..74a0956 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQConnectionDelegate_8_0.java
@@ -308,7 +308,7 @@
         {
             AMQSession s = (AMQSession) it.next();
             // _protocolHandler.addSessionByChannel(s.getChannelId(), s);
-            reopenChannel(s.getChannelId(), s.getDefaultPrefetchHigh(), s.getDefaultPrefetchLow(), s.getTransacted());
+            reopenChannel(s.getChannelId(), s.getDefaultPrefetchHigh(), s.getDefaultPrefetchLow(), s.isTransacted());
             s.resubscribe();
         }
     }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
index 1df809c..92602ac 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQDestination.java
@@ -829,7 +829,7 @@
         dest.setSubject(_subject);
         dest.setCreate(_create); 
         dest.setAssert(_assert); 
-        dest.setDelete(_create); 
+        dest.setDelete(_delete); 
         dest.setBrowseOnly(_browseOnly);
         dest.setAddressType(_addressType);
         dest.setTargetNode(_targetNode);
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
index 8984b7c..784b75a 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession.java
@@ -256,7 +256,7 @@
     protected AMQConnection _connection;
 
     /** Used to indicate whether or not this is a transactional session. */
-    protected boolean _transacted;
+    protected final boolean _transacted;
 
     /** Holds the sessions acknowledgement mode. */
     protected final int _acknowledgeMode;
@@ -371,7 +371,7 @@
      * Set when the dispatcher should direct incoming messages straight into the UnackedMessage list instead of
      * to the syncRecieveQueue or MessageListener. Used during cleanup, e.g. in Session.recover().
      */
-    private volatile boolean _usingDispatcherForCleanup;
+    protected volatile boolean _usingDispatcherForCleanup;
 
     /** Used to indicates that the connection to which this session belongs, has been stopped. */
     private boolean _connectionStopped;
@@ -1583,6 +1583,11 @@
         return _prefetchLowMark;
     }
 
+    public int getPrefetch()
+    {
+        return _prefetchHighMark;
+    }
+
     public AMQShortString getDefaultQueueExchangeName()
     {
         return _connection.getDefaultQueueExchangeName();
@@ -1614,7 +1619,24 @@
         return _ticket;
     }
 
-    public boolean getTransacted()
+    /**
+     * Indicates whether the session is in transacted mode.
+     *
+     * @return true if the session is in transacted mode
+     * @throws IllegalStateException - if session is closed.
+     */
+    public boolean getTransacted() throws JMSException
+    {
+        // Sun TCK checks that javax.jms.IllegalStateException is thrown for closed session
+        // nowhere else this behavior is documented
+        checkNotClosed();
+        return _transacted;
+    }
+
+    /**
+     * Indicates whether the session is in transacted mode.
+     */
+    public boolean isTransacted()
     {
         return _transacted;
     }
@@ -3047,7 +3069,7 @@
      */
     public boolean prefetch()
     {
-        return getAMQConnection().getMaxPrefetch() > 0;
+        return _prefetchHighMark > 0;
     }
 
     /** Signifies that the session has pending sends to commit. */
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
index 756b5ca..49b77dc 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_10.java
@@ -30,7 +30,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Queue;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.UUID;
@@ -60,23 +59,7 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.transport.ExchangeBoundResult;
-import org.apache.qpid.transport.ExchangeQueryResult;
-import org.apache.qpid.transport.ExecutionErrorCode;
-import org.apache.qpid.transport.ExecutionException;
-import org.apache.qpid.transport.MessageAcceptMode;
-import org.apache.qpid.transport.MessageAcquireMode;
-import org.apache.qpid.transport.MessageCreditUnit;
-import org.apache.qpid.transport.MessageFlowMode;
-import org.apache.qpid.transport.MessageTransfer;
-import org.apache.qpid.transport.Option;
-import org.apache.qpid.transport.QueueQueryResult;
-import org.apache.qpid.transport.Range;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Session;
-import org.apache.qpid.transport.SessionException;
-import org.apache.qpid.transport.SessionListener;
-import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.*;
 import org.apache.qpid.util.Serial;
 import org.apache.qpid.util.Strings;
 import org.slf4j.Logger;
@@ -141,13 +124,13 @@
 
     private long maxAckDelay = Long.getLong("qpid.session.max_ack_delay", 1000);
     private TimerTask flushTask = null;
-    private RangeSet unacked = new RangeSet();
+    private RangeSet unacked = RangeSetFactory.createRangeSet();
     private int unackedCount = 0;    
 
     /**
      * Used to store the range of in tx messages
      */
-    private final RangeSet _txRangeSet = new RangeSet();
+    private final RangeSet _txRangeSet = RangeSetFactory.createRangeSet();
     private int _txSize = 0;    
     //--- constructors
 
@@ -460,7 +443,7 @@
     public void sendRecover() throws AMQException, FailoverException
     {
         // release all unacked messages
-        RangeSet all = new RangeSet();
+        RangeSet all = RangeSetFactory.createRangeSet();
         RangeSet delivered = gatherRangeSet(_unacknowledgedMessageTags);
         RangeSet prefetched = gatherRangeSet(_prefetchedMessageTags);
         for (Iterator<Range> deliveredIter = delivered.iterator(); deliveredIter.hasNext();)
@@ -483,7 +466,7 @@
 
     private RangeSet gatherRangeSet(ConcurrentLinkedQueue<Long> messageTags)
     {
-        RangeSet ranges = new RangeSet();
+        RangeSet ranges = RangeSetFactory.createRangeSet();
         while (true)
         {
             Long tag = messageTags.poll();
@@ -518,7 +501,7 @@
     public void rejectMessage(long deliveryTag, boolean requeue)
     {
         // The value of requeue is always true
-        RangeSet ranges = new RangeSet();
+        RangeSet ranges = RangeSetFactory.createRangeSet();
         ranges.add((int) deliveryTag);
         flushProcessed(ranges, false);
         if (requeue)
@@ -812,11 +795,43 @@
     {
         if (suspend)
         {
-            for (BasicMessageConsumer consumer : _consumers.values())
-            {
-                getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()),
-                                             Option.UNRELIABLE);
-            }
+                synchronized (getMessageDeliveryLock())
+                {
+                    for (BasicMessageConsumer consumer : _consumers.values())
+	            {
+	                getQpidSession().messageStop(String.valueOf(consumer.getConsumerTag()),
+	                                             Option.UNRELIABLE);
+	                sync();
+	                List<Long> tags = consumer.drainReceiverQueueAndRetrieveDeliveryTags();
+	                _prefetchedMessageTags.addAll(tags);
+	            }
+                }
+
+                _usingDispatcherForCleanup = true;
+                syncDispatchQueue();
+                _usingDispatcherForCleanup = false;
+
+                RangeSet delivered = gatherRangeSet(_unacknowledgedMessageTags);
+		RangeSet prefetched = gatherRangeSet(_prefetchedMessageTags);
+		RangeSet all = RangeSetFactory.createRangeSet(delivered.size()
+					+ prefetched.size());
+
+		for (Iterator<Range> deliveredIter = delivered.iterator(); deliveredIter.hasNext();)
+		{
+			Range range = deliveredIter.next();
+			all.add(range);
+		}
+
+		for (Iterator<Range> prefetchedIter = prefetched.iterator(); prefetchedIter.hasNext();)
+		{
+			Range range = prefetchedIter.next();
+			all.add(range);
+		}
+
+		flushProcessed(all, false);
+		getQpidSession().messageRelease(delivered,Option.SET_REDELIVERED);
+		getQpidSession().messageRelease(prefetched);
+		sync();
         }
         else
         {
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
index 96df463..7daebbf 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQSession_0_8.java
@@ -21,6 +21,8 @@
 package org.apache.qpid.client;
 
 
+import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.ArrayList;
 import java.util.Map;
 
@@ -80,7 +82,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public final class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8>
+public class AMQSession_0_8 extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8>
 {
     /** Used for debugging. */
     private static final Logger _logger = LoggerFactory.getLogger(AMQSession.class);
@@ -96,8 +98,8 @@
      * @param defaultPrefetchHighMark The maximum number of messages to prefetched before suspending the session.
      * @param defaultPrefetchLowMark  The number of prefetched messages at which to resume the session.
      */
-    AMQSession_0_8(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode,
-               MessageFactoryRegistry messageFactoryRegistry, int defaultPrefetchHighMark, int defaultPrefetchLowMark)
+    protected AMQSession_0_8(AMQConnection con, int channelId, boolean transacted, int acknowledgeMode,
+                             MessageFactoryRegistry messageFactoryRegistry, int defaultPrefetchHighMark, int defaultPrefetchLowMark)
     {
 
          super(con,channelId,transacted,acknowledgeMode,messageFactoryRegistry,defaultPrefetchHighMark,defaultPrefetchLowMark);
@@ -150,7 +152,7 @@
             _logger.debug("Sending ack for delivery tag " + deliveryTag + " on channel " + _channelId);
         }
 
-        getProtocolHandler().writeFrame(ackFrame);
+        getProtocolHandler().writeFrame(ackFrame, !isTransacted());
         _unacknowledgedMessageTags.remove(deliveryTag);
     }
 
@@ -512,7 +514,7 @@
                     // Bounced message is processed here, away from the mina thread
                     AbstractJMSMessage bouncedMessage =
                             _messageFactoryRegistry.createMessage(0, false, msg.getExchange(),
-                                                                  msg.getRoutingKey(), msg.getContentHeader(), msg.getBodies());
+                                                                  msg.getRoutingKey(), msg.getContentHeader(), msg.getBodies(),_queueDestinationCache,_topicDestinationCache);
                     AMQConstant errorCode = AMQConstant.getConstant(msg.getReplyCode());
                     AMQShortString reason = msg.getReplyText();
                     _logger.debug("Message returned with error code " + errorCode + " (" + reason + ")");
@@ -572,6 +574,16 @@
                  }, _connection).execute();
     }
 
+    public DestinationCache<AMQQueue> getQueueDestinationCache()
+    {
+        return _queueDestinationCache;
+    }
+
+    public DestinationCache<AMQTopic> getTopicDestinationCache()
+    {
+        return _topicDestinationCache;
+    }
+
     class QueueDeclareOkHandler extends SpecificMethodFrameListener
     {
 
@@ -613,12 +625,12 @@
         return okHandler._messageCount;
     }
 
-    protected final boolean tagLE(long tag1, long tag2)
+    protected boolean tagLE(long tag1, long tag2)
     {
         return tag1 <= tag2;
     }
 
-    protected final boolean updateRollbackMark(long currentMark, long deliveryTag)
+    protected boolean updateRollbackMark(long currentMark, long deliveryTag)
     {
         return false;
     }
@@ -695,4 +707,55 @@
             return null;
         }
     }
+
+    public abstract static class DestinationCache<T extends AMQDestination>
+    {
+        private final Map<AMQShortString, Map<AMQShortString, T>> cache = new HashMap<AMQShortString, Map<AMQShortString, T>>();
+
+        public T getDestination(AMQShortString exchangeName, AMQShortString routingKey)
+        {
+            Map<AMQShortString, T> routingMap = cache.get(exchangeName);
+            if(routingMap == null)
+            {
+                routingMap = new LinkedHashMap<AMQShortString, T>()
+                {
+
+                    protected boolean removeEldestEntry(Map.Entry<AMQShortString, T> eldest)
+                    {
+                        return size() >= 200;
+                    }
+                };
+                cache.put(exchangeName,routingMap);
+            }
+            T destination = routingMap.get(routingKey);
+            if(destination == null)
+            {
+                destination = newDestination(exchangeName, routingKey);
+                routingMap.put(routingKey,destination);
+            }
+            return destination;
+        }
+
+        protected abstract T newDestination(AMQShortString exchangeName, AMQShortString routingKey);
+    }
+
+    private static class TopicDestinationCache extends DestinationCache<AMQTopic>
+    {
+        protected AMQTopic newDestination(AMQShortString exchangeName, AMQShortString routingKey)
+        {
+            return new AMQTopic(exchangeName, routingKey, null);
+        }
+    }
+
+    private static class QueueDestinationCache extends DestinationCache<AMQQueue>
+    {
+        protected AMQQueue newDestination(AMQShortString exchangeName, AMQShortString routingKey)
+        {
+            return new AMQQueue(exchangeName, routingKey, routingKey);
+        }
+    }
+
+    private final TopicDestinationCache _topicDestinationCache = new TopicDestinationCache();
+    private final QueueDestinationCache _queueDestinationCache = new QueueDestinationCache();
+
 }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
index bb27788..3b6179d 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_10.java
@@ -272,10 +272,8 @@
      */
     private void acknowledgeMessage(final AbstractJMSMessage message) throws AMQException
     {
-        final RangeSet ranges = new RangeSet();
-        ranges.add((int) message.getDeliveryTag());
         _0_10session.messageAcknowledge
-            (ranges,
+            (Range.newInstance((int) message.getDeliveryTag()),
              _acknowledgeMode != org.apache.qpid.jms.Session.NO_ACKNOWLEDGE);
 
         final AMQException amqe = _0_10session.getCurrentException();
@@ -294,9 +292,7 @@
      */
     private void flushUnwantedMessage(final AbstractJMSMessage message) throws AMQException
     {
-        final RangeSet ranges = new RangeSet();
-        ranges.add((int) message.getDeliveryTag());
-        _0_10session.flushProcessed(ranges,false);
+        _0_10session.flushProcessed(Range.newInstance((int) message.getDeliveryTag()),false);
 
         final AMQException amqe = _0_10session.getCurrentException();
         if (amqe != null)
@@ -315,10 +311,8 @@
     private boolean acquireMessage(final AbstractJMSMessage message) throws AMQException
     {
         boolean result = false;
-        final RangeSet ranges = new RangeSet();
-        ranges.add((int) message.getDeliveryTag());
 
-        final Acquired acq = _0_10session.getQpidSession().messageAcquire(ranges).get();
+        final Acquired acq = _0_10session.getQpidSession().messageAcquire(Range.newInstance((int)message.getDeliveryTag())).get();
 
         final RangeSet acquired = acq.getTransfers();
         if (acquired != null && acquired.size() > 0)
@@ -451,7 +445,7 @@
     {
         if (_synchronousQueue.size() > 0)
         {
-            RangeSet ranges = new RangeSet();
+            RangeSet ranges = RangeSetFactory.createRangeSet();
             Iterator iterator = _synchronousQueue.iterator();
             while (iterator.hasNext())
             {
@@ -551,7 +545,7 @@
         }
         else if (getSession().prefetch())
         {
-            capacity = _0_10session.getAMQConnection().getMaxPrefetch();
+            capacity = getSession().getPrefetch();
         }
         return capacity;
     }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
index efcbfd5..b2f4fce 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageConsumer_0_8.java
@@ -38,11 +38,13 @@
 public class BasicMessageConsumer_0_8 extends BasicMessageConsumer<UnprocessedMessage_0_8>
 {
     protected final Logger _logger = LoggerFactory.getLogger(getClass());
+    private AMQSession_0_8.DestinationCache<AMQTopic> _topicDestinationCache;
+    private AMQSession_0_8.DestinationCache<AMQQueue> _queueDestinationCache;
 
     private final RejectBehaviour _rejectBehaviour;
 
     protected BasicMessageConsumer_0_8(int channelId, AMQConnection connection, AMQDestination destination,
-                                       String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession session,
+                                       String messageSelector, boolean noLocal, MessageFactoryRegistry messageFactory, AMQSession_0_8 session,
                                        AMQProtocolHandler protocolHandler, FieldTable rawSelector, int prefetchHigh, int prefetchLow,
                                        boolean exclusive, int acknowledgeMode, boolean browseOnly, boolean autoClose) throws JMSException
     {
@@ -60,6 +62,9 @@
             consumerArguments.put(AMQPFilterTypes.NO_CONSUME.getValue(), Boolean.TRUE);
         }
 
+        _topicDestinationCache = session.getTopicDestinationCache();
+        _queueDestinationCache = session.getQueueDestinationCache();
+
         if (destination.getRejectBehaviour() != null)
         {
             _rejectBehaviour = destination.getRejectBehaviour();
@@ -100,7 +105,8 @@
 
         return _messageFactory.createMessage(messageFrame.getDeliveryTag(),
                                              messageFrame.isRedelivered(), messageFrame.getExchange(),
-                                             messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies());
+                                             messageFrame.getRoutingKey(), messageFrame.getContentHeader(), messageFrame.getBodies(),
+                _queueDestinationCache, _topicDestinationCache);
 
     }
 
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
index 34d2ade..b2f998c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/BasicMessageProducer_0_8.java
@@ -40,6 +40,7 @@
 import org.apache.qpid.framing.ContentBody;
 import org.apache.qpid.framing.ContentHeaderBody;
 import org.apache.qpid.framing.ExchangeDeclareBody;
+import org.apache.qpid.framing.MethodRegistry;
 
 public class BasicMessageProducer_0_8 extends BasicMessageProducer
 {
@@ -53,15 +54,17 @@
     void declareDestination(AMQDestination destination)
     {
 
-        ExchangeDeclareBody body = getSession().getMethodRegistry().createExchangeDeclareBody(_session.getTicket(),
-                                                                                              destination.getExchangeName(),
-                                                                                              destination.getExchangeClass(),
-                                                                                              false,
-                                                                                              false,
-                                                                                              false,
-                                                                                              false,
-                                                                                              true,
-                                                                                              null);
+        final MethodRegistry methodRegistry = getSession().getMethodRegistry();
+        ExchangeDeclareBody body =
+                methodRegistry.createExchangeDeclareBody(_session.getTicket(),
+                                                         destination.getExchangeName(),
+                                                         destination.getExchangeClass(),
+                                                         destination.getExchangeName().toString().startsWith("amq."),
+                                                         false,
+                                                         false,
+                                                         false,
+                                                         true,
+                                                         null);
         // Declare the exchange
         // Note that the durable and internal arguments are ignored since passive is set to false
 
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/filter/JMSSelectorFilter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/JMSSelectorFilter.java
new file mode 100644
index 0000000..14cce0a
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/JMSSelectorFilter.java
@@ -0,0 +1,209 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.qpid.client.filter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.AMQInternalException;
+import org.apache.qpid.client.message.AbstractJMSMessage;
+import org.apache.qpid.filter.FilterableMessage;
+import org.apache.qpid.filter.SelectorParsingException;
+import org.apache.qpid.filter.selector.ParseException;
+import org.apache.qpid.filter.selector.SelectorParser;
+import org.apache.qpid.filter.BooleanExpression;
+import org.apache.qpid.filter.selector.TokenMgrError;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+
+
+public class JMSSelectorFilter implements MessageFilter
+{
+    private static final Logger _logger = LoggerFactory.getLogger(JMSSelectorFilter.class);
+
+    private final String _selector;
+    private final BooleanExpression _matcher;
+
+    public JMSSelectorFilter(String selector) throws AMQInternalException
+    {
+        if (selector == null || "".equals(selector))
+        {
+            throw new IllegalArgumentException("Cannot create a JMSSelectorFilter with a null or empty selector string");
+        }
+        _selector = selector;
+        if (_logger.isDebugEnabled())
+        {
+            _logger.debug("Created JMSSelectorFilter with selector:" + _selector);
+        }
+        try
+        {
+            _matcher = new SelectorParser().parse(selector);
+        }
+        catch (SelectorParsingException e)
+        {
+            throw new AMQInternalException("Unable to parse selector \""+selector+"\"", e);
+        }
+        catch (TokenMgrError e)
+        {
+            throw new AMQInternalException("Unable to parse selector \""+selector+"\"", e);
+        }
+    }
+
+    public boolean matches(AbstractJMSMessage message)
+    {
+        try
+        {
+            boolean match = _matcher.matches(wrap(message));
+            if (_logger.isDebugEnabled())
+            {
+                _logger.debug(message + " match(" + match + ") selector(" + _selector + "): " + _selector);
+            }
+            return match;
+        }
+        catch (SelectorParsingException e)
+        {
+            _logger.warn("Caught exception when evaluating message selector for message  " + message, e);
+        }
+        return false;
+    }
+
+    private FilterableMessage wrap(final AbstractJMSMessage message)
+    {
+        return new FilterableMessage()
+        {
+            public boolean isPersistent()
+            {
+                try
+                {
+                    return message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT;
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public boolean isRedelivered()
+            {
+                try
+                {
+                    return message.getJMSRedelivered();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public Object getHeader(String name)
+            {
+                try
+                {
+                    return message.getObjectProperty(name);
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public String getReplyTo()
+            {
+                return message.getReplyToString();
+            }
+
+            public String getType()
+            {
+                try
+                {
+                    return message.getJMSType();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public byte getPriority()
+            {
+                try
+                {
+                    return (byte) message.getJMSPriority();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public String getMessageId()
+            {
+                try
+                {
+                    return message.getJMSMessageID();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public long getTimestamp()
+            {
+                try
+                {
+                    return message.getJMSTimestamp();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public String getCorrelationId()
+            {
+                try
+                {
+                    return message.getJMSCorrelationID();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+
+            public long getExpiration()
+            {
+                try
+                {
+                    return message.getJMSExpiration();
+                }
+                catch (JMSException e)
+                {
+                    throw new SelectorParsingException(e);
+                }
+            }
+        };
+    }
+
+    public String getSelector()
+    {
+        return _selector;
+    }
+}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/MessageFilter.java
similarity index 95%
rename from qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java
rename to qpid/java/client/src/main/java/org/apache/qpid/client/filter/MessageFilter.java
index ec0e8ea..fec78d6 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/filter/MessageFilter.java
@@ -15,7 +15,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.qpid.filter;
+package org.apache.qpid.client.filter;
 
 import org.apache.qpid.client.message.AbstractJMSMessage;
 
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java
index 6237234..33ca584 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/handler/BasicDeliverMethodHandler.java
@@ -48,7 +48,10 @@
                 body.getExchange(),
                 body.getRoutingKey(),
                 body.getRedelivered());
-        _logger.debug("New JmsDeliver method received:" + session);
+        if(_logger.isDebugEnabled())
+        {
+            _logger.debug("New JmsDeliver method received:" + session);
+        }
         session.unprocessedMessageReceived(channelId, msg);
     }
 }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
index f360b54..179ebd6 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_10.java
@@ -124,7 +124,7 @@
      */
     public static void updateExchangeTypeMapping(Header header, org.apache.qpid.transport.Session session)
     {
-        DeliveryProperties deliveryProps = header.get(DeliveryProperties.class);
+        DeliveryProperties deliveryProps = header.getDeliveryProperties();
         if (deliveryProps != null)
         {
             String exchange = deliveryProps.getExchange();
@@ -132,7 +132,7 @@
                     
         }
         
-        MessageProperties msgProps = header.get(MessageProperties.class);
+        MessageProperties msgProps = header.getMessageProperties();
         if (msgProps != null && msgProps.getReplyTo() != null)
         {
             String exchange = msgProps.getReplyTo().getExchange();
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
index 9ab0341..ab7061c 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AMQMessageDelegate_0_8.java
@@ -31,12 +31,7 @@
 import javax.jms.JMSException;
 import javax.jms.MessageNotWriteableException;
 
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQQueue;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.AMQTopic;
-import org.apache.qpid.client.CustomJMSXProperty;
-import org.apache.qpid.client.JMSAMQException;
+import org.apache.qpid.client.*;
 import org.apache.qpid.collections.ReferenceMap;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.BasicContentHeaderProperties;
@@ -81,7 +76,8 @@
 
     // Used when generating a received message object
     protected AMQMessageDelegate_0_8(long deliveryTag, BasicContentHeaderProperties contentHeader, AMQShortString exchange,
-                                     AMQShortString routingKey) 
+                                     AMQShortString routingKey, AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache,
+                                                         AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache)
     {
         this(contentHeader, deliveryTag);
 
@@ -95,10 +91,10 @@
             switch (type.intValue())
             {
                 case AMQDestination.QUEUE_TYPE:
-                    dest = new AMQQueue(exchange, routingKey, routingKey);
+                    dest = queueDestinationCache.getDestination(exchange, routingKey);
                     break;
                 case AMQDestination.TOPIC_TYPE:
-                    dest = new AMQTopic(exchange, routingKey, null);
+                    dest = topicDestinationCache.getDestination(exchange, routingKey);
                     break;
                 default:
                     // Use the generateDestination method
@@ -133,10 +129,66 @@
     {
         if (messageId != null)
         {
-            getContentHeaderProperties().setMessageId("ID:" + messageId);
+            getContentHeaderProperties().setMessageId(asShortStringMsgId(messageId));
         }
     }
 
+    private static final byte[] HEX_DIGITS = {0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,
+                                              0x61,0x62,0x63,0x64,0x65,0x66};
+
+    private static AMQShortString asShortStringMsgId(UUID messageId)
+    {
+        long msb = messageId.getMostSignificantBits();
+        long lsb = messageId.getLeastSignificantBits();
+
+        byte[] messageIdBytes = new byte[39];
+        messageIdBytes[0] = (byte) 'I';
+        messageIdBytes[1] = (byte) 'D';
+        messageIdBytes[2] = (byte) ':';
+
+        messageIdBytes[3] = HEX_DIGITS[(int)((msb >> 60) & 0xFl)];
+        messageIdBytes[4] = HEX_DIGITS[(int)((msb >> 56) & 0xFl)];
+        messageIdBytes[5] = HEX_DIGITS[(int)((msb >> 52) & 0xFl)];
+        messageIdBytes[6] = HEX_DIGITS[(int)((msb >> 48) & 0xFl)];
+        messageIdBytes[7] = HEX_DIGITS[(int)((msb >> 44) & 0xFl)];
+        messageIdBytes[8] = HEX_DIGITS[(int)((msb >> 40) & 0xFl)];
+        messageIdBytes[9] = HEX_DIGITS[(int)((msb >> 36) & 0xFl)];
+        messageIdBytes[10] = HEX_DIGITS[(int)((msb >> 32) & 0xFl)];
+
+        messageIdBytes[11] = (byte) '-';
+        messageIdBytes[12] = HEX_DIGITS[(int)((msb >> 28) & 0xFl)];
+        messageIdBytes[13] = HEX_DIGITS[(int)((msb >> 24) & 0xFl)];
+        messageIdBytes[14] = HEX_DIGITS[(int)((msb >> 20) & 0xFl)];
+        messageIdBytes[15] = HEX_DIGITS[(int)((msb >> 16) & 0xFl)];
+        messageIdBytes[16] = (byte) '-';
+        messageIdBytes[17] = HEX_DIGITS[(int)((msb >> 12) & 0xFl)];
+        messageIdBytes[18] = HEX_DIGITS[(int)((msb >> 8) & 0xFl)];
+        messageIdBytes[19] = HEX_DIGITS[(int)((msb >> 4) & 0xFl)];
+        messageIdBytes[20] = HEX_DIGITS[(int)(msb & 0xFl)];
+        messageIdBytes[21] = (byte) '-';
+
+        messageIdBytes[22] = HEX_DIGITS[(int)((lsb >> 60) & 0xFl)];
+        messageIdBytes[23] = HEX_DIGITS[(int)((lsb >> 56) & 0xFl)];
+        messageIdBytes[24] = HEX_DIGITS[(int)((lsb >> 52) & 0xFl)];
+        messageIdBytes[25] = HEX_DIGITS[(int)((lsb >> 48) & 0xFl)];
+
+        messageIdBytes[26] = (byte) '-';
+
+        messageIdBytes[27] = HEX_DIGITS[(int)((lsb >> 44) & 0xFl)];
+        messageIdBytes[28] = HEX_DIGITS[(int)((lsb >> 40) & 0xFl)];
+        messageIdBytes[29] = HEX_DIGITS[(int)((lsb >> 36) & 0xFl)];
+        messageIdBytes[30] = HEX_DIGITS[(int)((lsb >> 32) & 0xFl)];
+        messageIdBytes[31] = HEX_DIGITS[(int)((lsb >> 28) & 0xFl)];
+        messageIdBytes[32] = HEX_DIGITS[(int)((lsb >> 24) & 0xFl)];
+        messageIdBytes[33] = HEX_DIGITS[(int)((lsb >> 20) & 0xFl)];
+        messageIdBytes[34] = HEX_DIGITS[(int)((lsb >> 16) & 0xFl)];
+        messageIdBytes[35] = HEX_DIGITS[(int)((lsb >> 12) & 0xFl)];
+        messageIdBytes[36] = HEX_DIGITS[(int)((lsb >> 8) & 0xFl)];
+        messageIdBytes[37] = HEX_DIGITS[(int)((lsb >> 4) & 0xFl)];
+        messageIdBytes[38] = HEX_DIGITS[(int)(lsb & 0xFl)];
+
+        return new AMQShortString(messageIdBytes,0,39);
+    }
 
     public long getJMSTimestamp() throws JMSException
     {
@@ -413,7 +465,7 @@
         }
 
         checkWritableProperties();
-        getJmsHeaders().setByte(propertyName, new Byte(b));
+        getJmsHeaders().setByte(propertyName, b);
     }
 
     public void setShortProperty(String propertyName, short i) throws JMSException
@@ -424,13 +476,13 @@
         }
 
         checkWritableProperties();
-        getJmsHeaders().setShort(propertyName, new Short(i));
+        getJmsHeaders().setShort(propertyName, i);
     }
 
     public void setIntProperty(String propertyName, int i) throws JMSException
     {
         checkWritableProperties();
-        getJmsHeaders().setInteger(propertyName, new Integer(i));
+        getJmsHeaders().setInteger(propertyName, i);
     }
 
     public void setLongProperty(String propertyName, long l) throws JMSException
@@ -441,7 +493,7 @@
         }
 
         checkWritableProperties();
-        getJmsHeaders().setLong(propertyName, new Long(l));
+        getJmsHeaders().setLong(propertyName, l);
     }
 
     public void setFloatProperty(String propertyName, float f) throws JMSException
@@ -452,7 +504,7 @@
         }
 
         checkWritableProperties();
-        getJmsHeaders().setFloat(propertyName, new Float(f));
+        getJmsHeaders().setFloat(propertyName, f);
     }
 
     public void setDoubleProperty(String propertyName, double v) throws JMSException
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
index 967a1fb..16b71db 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/AbstractJMSMessageFactory.java
@@ -21,6 +21,9 @@
 package org.apache.qpid.client.message;
 
 import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession_0_8;
+import org.apache.qpid.client.AMQTopic;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.ContentBody;
 import org.apache.qpid.framing.ContentHeaderBody;
@@ -44,7 +47,9 @@
 
     protected AbstractJMSMessage create08MessageWithBody(long messageNbr, ContentHeaderBody contentHeader,
                                                          AMQShortString exchange, AMQShortString routingKey,
-                                                         List bodies) throws AMQException
+                                                         List bodies,
+                                                         AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache,
+                                                         AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache) throws AMQException
     {
         ByteBuffer data;
         final boolean debug = _logger.isDebugEnabled();
@@ -99,7 +104,7 @@
 
         AMQMessageDelegate delegate = new AMQMessageDelegate_0_8(messageNbr,
                                                                  (BasicContentHeaderProperties) contentHeader.getProperties(),
-                                                                 exchange, routingKey);
+                                                                 exchange, routingKey, queueDestinationCache, topicDestinationCache);
 
         return createMessage(delegate, data);
     }
@@ -149,10 +154,12 @@
 
 
     public AbstractJMSMessage createMessage(long messageNbr, boolean redelivered, ContentHeaderBody contentHeader,
-                                            AMQShortString exchange, AMQShortString routingKey, List bodies)
+                                            AMQShortString exchange, AMQShortString routingKey, List bodies,
+                                                         AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache,
+                                                         AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache)
             throws JMSException, AMQException
     {
-        final AbstractJMSMessage msg = create08MessageWithBody(messageNbr, contentHeader, exchange, routingKey, bodies);
+        final AbstractJMSMessage msg = create08MessageWithBody(messageNbr, contentHeader, exchange, routingKey, bodies, queueDestinationCache, topicDestinationCache);
         msg.setJMSRedelivered(redelivered);
         msg.setReceivedFromServer();
         return msg;
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
index c981c95..7f733b9 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/JMSObjectMessage.java
@@ -29,6 +29,7 @@
 
 import org.apache.qpid.AMQException;
 import org.apache.qpid.client.util.ClassLoadingAwareObjectInputStream;
+import org.apache.qpid.util.ByteBufferInputStream;
 
 public class JMSObjectMessage extends AbstractJMSMessage implements ObjectMessage
 {
@@ -62,26 +63,7 @@
 
           try
           {
-              ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new InputStream()
-              {
-
-
-                  @Override
-                  public int read() throws IOException
-                  {
-                      return data.get();
-                  }
-
-                  @Override
-                  public int read(byte[] b, int off, int len) throws IOException
-                  {
-                      len = data.remaining() < len ? data.remaining() : len;
-                      data.get(b, off, len);
-                      return len;
-                  }
-              });
-
-              _readData = (Serializable) in.readObject();
+              _readData = read(data);
           }
           catch (IOException e)
           {
@@ -93,7 +75,6 @@
           }
       }
 
-
     public void clearBody() throws JMSException
     {
         super.clearBody();
@@ -189,24 +170,7 @@
             final ByteBuffer data = _data.duplicate();
             try
             {
-                ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new InputStream()
-                {
-                    @Override
-                    public int read() throws IOException
-                    {
-                        return data.get();
-                    }
-
-                    @Override
-                    public int read(byte[] b, int off, int len) throws IOException
-                    {
-                        len = data.remaining() < len ? data.remaining() : len;
-                        data.get(b, off, len);
-                        return len;
-                    }
-                });
-
-                return (Serializable) in.readObject();
+                return read(data);
             }
             catch (ClassNotFoundException e)
             {
@@ -224,4 +188,14 @@
 
     }
 
+    private Serializable read(final ByteBuffer data) throws IOException, ClassNotFoundException
+    {
+        Serializable result = null;
+        if (data != null && data.hasRemaining())
+        {
+            ClassLoadingAwareObjectInputStream in = new ClassLoadingAwareObjectInputStream(new ByteBufferInputStream(data));
+            result = (Serializable) in.readObject();
+        }
+        return result;
+    }
 }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
index f3d96cd..93c2872 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactory.java
@@ -25,6 +25,9 @@
 import javax.jms.JMSException;
 
 import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession_0_8;
+import org.apache.qpid.client.AMQTopic;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.ContentHeaderBody;
 import org.apache.qpid.transport.DeliveryProperties;
@@ -36,7 +39,7 @@
     AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered,
                                      ContentHeaderBody contentHeader,
                                      AMQShortString exchange, AMQShortString routingKey,
-                                     List bodies)
+                                     List bodies, AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache, AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache)
         throws JMSException, AMQException;
 
      AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered,
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
index cdb75fc..15ad3ed 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/message/MessageFactoryRegistry.java
@@ -28,6 +28,9 @@
 import javax.jms.JMSException;
 
 import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQSession_0_8;
+import org.apache.qpid.client.AMQTopic;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.BasicContentHeaderProperties;
 import org.apache.qpid.framing.ContentHeaderBody;
@@ -93,15 +96,19 @@
      * Create a message. This looks up the MIME type from the content header and instantiates the appropriate
      * concrete message type.
      *
+     *
      * @param deliveryTag   the AMQ message id
      * @param redelivered   true if redelivered
      * @param contentHeader the content header that was received
      * @param bodies        a list of ContentBody instances @return the message.
-     * @throws AMQException
+     * @param queueDestinationCache
+     *@param topicDestinationCache @throws AMQException
      * @throws JMSException
      */
     public AbstractJMSMessage createMessage(long deliveryTag, boolean redelivered, AMQShortString exchange,
-                                            AMQShortString routingKey, ContentHeaderBody contentHeader, List bodies)
+                                            AMQShortString routingKey, ContentHeaderBody contentHeader, List bodies,
+                                            AMQSession_0_8.DestinationCache<AMQQueue> queueDestinationCache,
+                                            AMQSession_0_8.DestinationCache<AMQTopic> topicDestinationCache)
             throws AMQException, JMSException
     {
         BasicContentHeaderProperties properties = (BasicContentHeaderProperties) contentHeader.getProperties();
@@ -118,13 +125,13 @@
             mf = _default;
         }
 
-        return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies);
+        return mf.createMessage(deliveryTag, redelivered, contentHeader, exchange, routingKey, bodies, queueDestinationCache, topicDestinationCache);
     }
 
     public AbstractJMSMessage createMessage(MessageTransfer transfer) throws AMQException, JMSException
     {
 
-        MessageProperties mprop = transfer.getHeader().get(MessageProperties.class);
+        MessageProperties mprop = transfer.getHeader().getMessageProperties();
         String messageType = "";
         if ( mprop == null || mprop.getContentType() == null)
         {
@@ -143,7 +150,7 @@
 
         boolean redelivered = false;
         DeliveryProperties deliverProps;
-        if((deliverProps = transfer.getHeader().get(DeliveryProperties.class)) != null)
+        if((deliverProps = transfer.getHeader().getDeliveryProperties()) != null)
         {
             redelivered = deliverProps.getRedelivered();
         }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
index 284954e..8911d4e 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/client/protocol/AMQProtocolHandler.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.client.protocol;
 
+import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -409,10 +410,10 @@
             final ArrayList<AMQDataBlock> dataBlocks = _codecFactory.getDecoder().decodeBuffer(msg);
 
             // Decode buffer
-
-            for (AMQDataBlock message : dataBlocks)
+            int size = dataBlocks.size();
+            for (int i = 0; i < size; i++)
             {
-
+                AMQDataBlock message = dataBlocks.get(i);
                     if (PROTOCOL_DEBUG)
                     {
                         _protocolLogger.info(String.format("RECV: [%s] %s", this, message));
@@ -420,10 +421,10 @@
 
                     if(message instanceof AMQFrame)
                     {
-                        final boolean debug = _logger.isDebugEnabled();
+
                         final long msgNumber = ++_messageReceivedCount;
 
-                        if (debug && ((msgNumber % 1000) == 0))
+                        if (((msgNumber % 1000) == 0) && _logger.isDebugEnabled())
                         {
                             _logger.debug("Received " + _messageReceivedCount + " protocol messages");
                         }
@@ -514,12 +515,20 @@
         return getStateManager().createWaiter(states);
     }
 
-    public  synchronized void writeFrame(AMQDataBlock frame)
+    public void writeFrame(AMQDataBlock frame)
+    {
+        writeFrame(frame, true);
+    }
+
+    public  synchronized void writeFrame(AMQDataBlock frame, boolean flush)
     {
         final ByteBuffer buf = asByteBuffer(frame);
         _writtenBytes += buf.remaining();
         _sender.send(buf);
-        _sender.flush();
+        if(flush)
+        {
+            _sender.flush();
+        }
 
         if (PROTOCOL_DEBUG)
         {
@@ -539,35 +548,51 @@
 
     }
 
+    private static final int REUSABLE_BYTE_BUFFER_CAPACITY = 65 * 1024;
+    private final byte[] _reusableBytes = new byte[REUSABLE_BYTE_BUFFER_CAPACITY];
+    private final ByteBuffer _reusableByteBuffer = ByteBuffer.wrap(_reusableBytes);
+    private final BytesDataOutput _reusableDataOutput = new BytesDataOutput(_reusableBytes);
+
     private ByteBuffer asByteBuffer(AMQDataBlock block)
     {
-        final ByteBuffer buf = ByteBuffer.allocate((int) block.getSize());
+        final int size = (int) block.getSize();
+
+        final byte[] data;
+
+
+        if(size > REUSABLE_BYTE_BUFFER_CAPACITY)
+        {
+            data= new byte[size];
+        }
+        else
+        {
+
+            data = _reusableBytes;
+        }
+        _reusableDataOutput.setBuffer(data);
 
         try
         {
-            block.writePayload(new DataOutputStream(new OutputStream()
-            {
-
-
-                @Override
-                public void write(int b) throws IOException
-                {
-                    buf.put((byte) b);
-                }
-
-                @Override
-                public void write(byte[] b, int off, int len) throws IOException
-                {
-                    buf.put(b, off, len);
-                }
-            }));
+            block.writePayload(_reusableDataOutput);
         }
         catch (IOException e)
         {
             throw new RuntimeException(e);
         }
 
-        buf.flip();
+        final ByteBuffer buf;
+
+        if(size < REUSABLE_BYTE_BUFFER_CAPACITY)
+        {
+            buf = _reusableByteBuffer;
+            buf.position(0);
+        }
+        else
+        {
+            buf = ByteBuffer.wrap(data);
+        }
+        buf.limit(_reusableDataOutput.length());
+
         return buf;
     }
 
@@ -840,4 +865,160 @@
         return _suggestedProtocolVersion;
     }
 
+    private static class BytesDataOutput implements DataOutput
+        {
+            int _pos = 0;
+            byte[] _buf;
+
+            public BytesDataOutput(byte[] buf)
+            {
+                _buf = buf;
+            }
+
+            public void setBuffer(byte[] buf)
+            {
+                _buf = buf;
+                _pos = 0;
+            }
+
+            public void reset()
+            {
+                _pos = 0;
+            }
+
+            public int length()
+            {
+                return _pos;
+            }
+
+            public void write(int b)
+            {
+                _buf[_pos++] = (byte) b;
+            }
+
+            public void write(byte[] b)
+            {
+                System.arraycopy(b, 0, _buf, _pos, b.length);
+                _pos+=b.length;
+            }
+
+
+            public void write(byte[] b, int off, int len)
+            {
+                System.arraycopy(b, off, _buf, _pos, len);
+                _pos+=len;
+
+            }
+
+            public void writeBoolean(boolean v)
+            {
+                _buf[_pos++] = v ? (byte) 1 : (byte) 0;
+            }
+
+            public void writeByte(int v)
+            {
+                _buf[_pos++] = (byte) v;
+            }
+
+            public void writeShort(int v)
+            {
+                _buf[_pos++] = (byte) (v >>> 8);
+                _buf[_pos++] = (byte) v;
+            }
+
+            public void writeChar(int v)
+            {
+                _buf[_pos++] = (byte) (v >>> 8);
+                _buf[_pos++] = (byte) v;
+            }
+
+            public void writeInt(int v)
+            {
+                _buf[_pos++] = (byte) (v >>> 24);
+                _buf[_pos++] = (byte) (v >>> 16);
+                _buf[_pos++] = (byte) (v >>> 8);
+                _buf[_pos++] = (byte) v;
+            }
+
+            public void writeLong(long v)
+            {
+                _buf[_pos++] = (byte) (v >>> 56);
+                _buf[_pos++] = (byte) (v >>> 48);
+                _buf[_pos++] = (byte) (v >>> 40);
+                _buf[_pos++] = (byte) (v >>> 32);
+                _buf[_pos++] = (byte) (v >>> 24);
+                _buf[_pos++] = (byte) (v >>> 16);
+                _buf[_pos++] = (byte) (v >>> 8);
+                _buf[_pos++] = (byte)v;
+            }
+
+            public void writeFloat(float v)
+            {
+                writeInt(Float.floatToIntBits(v));
+            }
+
+            public void writeDouble(double v)
+            {
+                writeLong(Double.doubleToLongBits(v));
+            }
+
+            public void writeBytes(String s)
+            {
+                int len = s.length();
+                for (int i = 0 ; i < len ; i++)
+                {
+                    _buf[_pos++] = ((byte)s.charAt(i));
+                }
+            }
+
+            public void writeChars(String s)
+            {
+                int len = s.length();
+                for (int i = 0 ; i < len ; i++)
+                {
+                    int v = s.charAt(i);
+                    _buf[_pos++] = (byte) (v >>> 8);
+                    _buf[_pos++] = (byte) v;
+                }
+            }
+
+            public void writeUTF(String s)
+            {
+                int strlen = s.length();
+
+                int pos = _pos;
+                _pos+=2;
+
+
+                for (int i = 0; i < strlen; i++)
+                {
+                    int c = s.charAt(i);
+                    if ((c >= 0x0001) && (c <= 0x007F))
+                    {
+                        c = s.charAt(i);
+                        _buf[_pos++] = (byte) c;
+
+                    }
+                    else if (c > 0x07FF)
+                    {
+                        _buf[_pos++]  = (byte) (0xE0 | ((c >> 12) & 0x0F));
+                        _buf[_pos++]  = (byte) (0x80 | ((c >>  6) & 0x3F));
+                        _buf[_pos++]  = (byte) (0x80 | (c & 0x3F));
+                    }
+                    else
+                    {
+                        _buf[_pos++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
+                        _buf[_pos++]  = (byte) (0x80 | (c & 0x3F));
+                    }
+                }
+
+                int len = _pos - (pos + 2);
+
+                _buf[pos++] = (byte) (len >>> 8);
+                _buf[pos] = (byte) len;
+            }
+
+        }
+
+
 }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/ArithmeticExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/ArithmeticExpression.java
deleted file mode 100644
index a86613f..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/ArithmeticExpression.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-
-/**
- * An expression which performs an operation on two expression values
- */
-public abstract class ArithmeticExpression extends BinaryExpression
-{
-
-    protected static final int INTEGER = 1;
-    protected static final int LONG = 2;
-    protected static final int DOUBLE = 3;
-
-
-    public ArithmeticExpression(Expression left, Expression right)
-    {
-        super(left, right);
-    }
-
-    public static Expression createPlus(Expression left, Expression right)
-    {
-        return new ArithmeticExpression(left, right)
-            {
-                protected Object evaluate(Object lvalue, Object rvalue)
-                {
-                    if (lvalue instanceof String)
-                    {
-                        String text = (String) lvalue;
-                        return text + rvalue;
-                    }
-                    else if (lvalue instanceof Number)
-                    {
-                        return plus((Number) lvalue, asNumber(rvalue));
-                    }
-
-                    throw new RuntimeException("Cannot call plus operation on: " + lvalue + " and: " + rvalue);
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "+";
-                }
-            };
-    }
-
-    public static Expression createMinus(Expression left, Expression right)
-    {
-        return new ArithmeticExpression(left, right)
-            {
-                protected Object evaluate(Object lvalue, Object rvalue)
-                {
-                    if (lvalue instanceof Number)
-                    {
-                        return minus((Number) lvalue, asNumber(rvalue));
-                    }
-
-                    throw new RuntimeException("Cannot call minus operation on: " + lvalue + " and: " + rvalue);
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "-";
-                }
-            };
-    }
-
-    public static Expression createMultiply(Expression left, Expression right)
-    {
-        return new ArithmeticExpression(left, right)
-            {
-
-                protected Object evaluate(Object lvalue, Object rvalue)
-                {
-                    if (lvalue instanceof Number)
-                    {
-                        return multiply((Number) lvalue, asNumber(rvalue));
-                    }
-
-                    throw new RuntimeException("Cannot call multiply operation on: " + lvalue + " and: " + rvalue);
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "*";
-                }
-            };
-    }
-
-    public static Expression createDivide(Expression left, Expression right)
-    {
-        return new ArithmeticExpression(left, right)
-            {
-
-                protected Object evaluate(Object lvalue, Object rvalue)
-                {
-                    if (lvalue instanceof Number)
-                    {
-                        return divide((Number) lvalue, asNumber(rvalue));
-                    }
-
-                    throw new RuntimeException("Cannot call divide operation on: " + lvalue + " and: " + rvalue);
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "/";
-                }
-            };
-    }
-
-    public static Expression createMod(Expression left, Expression right)
-    {
-        return new ArithmeticExpression(left, right)
-            {
-
-                protected Object evaluate(Object lvalue, Object rvalue)
-                {
-                    if (lvalue instanceof Number)
-                    {
-                        return mod((Number) lvalue, asNumber(rvalue));
-                    }
-
-                    throw new RuntimeException("Cannot call mod operation on: " + lvalue + " and: " + rvalue);
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "%";
-                }
-            };
-    }
-
-    protected Number plus(Number left, Number right)
-    {
-        switch (numberType(left, right))
-        {
-
-        case ArithmeticExpression.INTEGER:
-            return new Integer(left.intValue() + right.intValue());
-
-        case ArithmeticExpression.LONG:
-            return new Long(left.longValue() + right.longValue());
-
-        default:
-            return new Double(left.doubleValue() + right.doubleValue());
-        }
-    }
-
-    protected Number minus(Number left, Number right)
-    {
-        switch (numberType(left, right))
-        {
-
-        case ArithmeticExpression.INTEGER:
-            return new Integer(left.intValue() - right.intValue());
-
-        case ArithmeticExpression.LONG:
-            return new Long(left.longValue() - right.longValue());
-
-        default:
-            return new Double(left.doubleValue() - right.doubleValue());
-        }
-    }
-
-    protected Number multiply(Number left, Number right)
-    {
-        switch (numberType(left, right))
-        {
-
-        case ArithmeticExpression.INTEGER:
-            return new Integer(left.intValue() * right.intValue());
-
-        case ArithmeticExpression.LONG:
-            return new Long(left.longValue() * right.longValue());
-
-        default:
-            return new Double(left.doubleValue() * right.doubleValue());
-        }
-    }
-
-    protected Number divide(Number left, Number right)
-    {
-        return new Double(left.doubleValue() / right.doubleValue());
-    }
-
-    protected Number mod(Number left, Number right)
-    {
-        return new Double(left.doubleValue() % right.doubleValue());
-    }
-
-    private int numberType(Number left, Number right)
-    {
-        if (isDouble(left) || isDouble(right))
-        {
-            return ArithmeticExpression.DOUBLE;
-        }
-        else if ((left instanceof Long) || (right instanceof Long))
-        {
-            return ArithmeticExpression.LONG;
-        }
-        else
-        {
-            return ArithmeticExpression.INTEGER;
-        }
-    }
-
-    private boolean isDouble(Number n)
-    {
-        return (n instanceof Float) || (n instanceof Double);
-    }
-
-    protected Number asNumber(Object value)
-    {
-        if (value instanceof Number)
-        {
-            return (Number) value;
-        }
-        else
-        {
-            throw new RuntimeException("Cannot convert value: " + value + " into a number");
-        }
-    }
-
-    public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-    {
-        Object lvalue = left.evaluate(message);
-        if (lvalue == null)
-        {
-            return null;
-        }
-
-        Object rvalue = right.evaluate(message);
-        if (rvalue == null)
-        {
-            return null;
-        }
-
-        return evaluate(lvalue, rvalue);
-    }
-
-    /**
-     * @param lvalue
-     * @param rvalue
-     * @return
-     */
-    protected abstract Object evaluate(Object lvalue, Object rvalue);
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/BinaryExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/BinaryExpression.java
deleted file mode 100644
index f97f858..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/BinaryExpression.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-/**
- * An expression which performs an operation on two expression values.
- */
-public abstract class BinaryExpression implements Expression
-{
-    protected Expression left;
-    protected Expression right;
-
-    public BinaryExpression(Expression left, Expression right)
-    {
-        this.left = left;
-        this.right = right;
-    }
-
-    public Expression getLeft()
-    {
-        return left;
-    }
-
-    public Expression getRight()
-    {
-        return right;
-    }
-
-    /**
-     * @see Object#toString()
-     */
-    public String toString()
-    {
-        return "(" + left.toString() + " " + getExpressionSymbol() + " " + right.toString() + ")";
-    }
-
-    /**
-     * TODO: more efficient hashCode()
-     *
-     * @see Object#hashCode()
-     */
-    public int hashCode()
-    {
-        return toString().hashCode();
-    }
-
-    /**
-     * TODO: more efficient hashCode()
-     *
-     * @see Object#equals(Object)
-     */
-    public boolean equals(Object o)
-    {
-
-        if ((o == null) || !this.getClass().equals(o.getClass()))
-        {
-            return false;
-        }
-
-        return toString().equals(o.toString());
-
-    }
-
-    /**
-     * Returns the symbol that represents this binary expression.  For example, addition is
-     * represented by "+"
-     *
-     * @return
-     */
-    public abstract String getExpressionSymbol();
-
-    /**
-     * @param expression
-     */
-    public void setRight(Expression expression)
-    {
-        right = expression;
-    }
-
-    /**
-     * @param expression
-     */
-    public void setLeft(Expression expression)
-    {
-        left = expression;
-    }
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/BooleanExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/BooleanExpression.java
deleted file mode 100644
index 14a5c7e..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/BooleanExpression.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-
-/**
- * A BooleanExpression is an expression that always
- * produces a Boolean result.
- */
-public interface BooleanExpression extends Expression
-{
-
-    public boolean matches(AbstractJMSMessage message) throws AMQInternalException;
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/ComparisonExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/ComparisonExpression.java
deleted file mode 100644
index 55fca85..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/ComparisonExpression.java
+++ /dev/null
@@ -1,589 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-/**
- * A filter performing a comparison of two objects
- */
-public abstract class ComparisonExpression extends BinaryExpression implements BooleanExpression
-{
-
-    public static BooleanExpression createBetween(Expression value, Expression left, Expression right)
-    {
-        return LogicExpression.createAND(ComparisonExpression.createGreaterThanEqual(value, left), ComparisonExpression.createLessThanEqual(value, right));
-    }
-
-    public static BooleanExpression createNotBetween(Expression value, Expression left, Expression right)
-    {
-        return LogicExpression.createOR(ComparisonExpression.createLessThan(value, left), ComparisonExpression.createGreaterThan(value, right));
-    }
-
-    private static final HashSet REGEXP_CONTROL_CHARS = new HashSet();
-
-    static
-    {
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('.'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('\\'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('['));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character(']'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('^'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('$'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('?'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('*'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('+'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('{'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('}'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('|'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('('));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character(')'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character(':'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('&'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('<'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('>'));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('='));
-        ComparisonExpression.REGEXP_CONTROL_CHARS.add(new Character('!'));
-    }
-
-    static class LikeExpression extends UnaryExpression implements BooleanExpression
-    {
-
-        Pattern likePattern;
-
-        /**
-         * @param right
-         */
-        public LikeExpression(Expression right, String like, int escape)
-        {
-            super(right);
-
-            StringBuffer regexp = new StringBuffer(like.length() * 2);
-            regexp.append("\\A"); // The beginning of the input
-            for (int i = 0; i < like.length(); i++)
-            {
-                char c = like.charAt(i);
-                if (escape == (0xFFFF & c))
-                {
-                    i++;
-                    if (i >= like.length())
-                    {
-                        // nothing left to escape...
-                        break;
-                    }
-
-                    char t = like.charAt(i);
-                    regexp.append("\\x");
-                    regexp.append(Integer.toHexString(0xFFFF & t));
-                }
-                else if (c == '%')
-                {
-                    regexp.append(".*?"); // Do a non-greedy match
-                }
-                else if (c == '_')
-                {
-                    regexp.append("."); // match one
-                }
-                else if (ComparisonExpression.REGEXP_CONTROL_CHARS.contains(new Character(c)))
-                {
-                    regexp.append("\\x");
-                    regexp.append(Integer.toHexString(0xFFFF & c));
-                }
-                else
-                {
-                    regexp.append(c);
-                }
-            }
-
-            regexp.append("\\z"); // The end of the input
-
-            likePattern = Pattern.compile(regexp.toString(), Pattern.DOTALL);
-        }
-
-        /**
-         *  org.apache.activemq.filter.UnaryExpression#getExpressionSymbol()
-         */
-        public String getExpressionSymbol()
-        {
-            return "LIKE";
-        }
-
-        /**
-         *  org.apache.activemq.filter.Expression#evaluate(MessageEvaluationContext)
-         */
-        public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-        {
-
-            Object rv = this.getRight().evaluate(message);
-
-            if (rv == null)
-            {
-                return null;
-            }
-
-            if (!(rv instanceof String))
-            {
-                return
-                    Boolean.FALSE;
-                    // throw new RuntimeException("LIKE can only operate on String identifiers.  LIKE attemped on: '" + rv.getClass());
-            }
-
-            return likePattern.matcher((String) rv).matches() ? Boolean.TRUE : Boolean.FALSE;
-        }
-
-        public boolean matches(AbstractJMSMessage message) throws AMQInternalException
-        {
-            Object object = evaluate(message);
-
-            return (object != null) && (object == Boolean.TRUE);
-        }
-    }
-
-    public static BooleanExpression createLike(Expression left, String right, String escape)
-    {
-        if ((escape != null) && (escape.length() != 1))
-        {
-            throw new RuntimeException(
-                "The ESCAPE string litteral is invalid.  It can only be one character.  Litteral used: " + escape);
-        }
-
-        int c = -1;
-        if (escape != null)
-        {
-            c = 0xFFFF & escape.charAt(0);
-        }
-
-        return new LikeExpression(left, right, c);
-    }
-
-    public static BooleanExpression createNotLike(Expression left, String right, String escape)
-    {
-        return UnaryExpression.createNOT(ComparisonExpression.createLike(left, right, escape));
-    }
-
-    public static BooleanExpression createInFilter(Expression left, List elements)
-    {
-
-        if (!(left instanceof PropertyExpression))
-        {
-            throw new RuntimeException("Expected a property for In expression, got: " + left);
-        }
-
-        return UnaryExpression.createInExpression((PropertyExpression) left, elements, false);
-
-    }
-
-    public static BooleanExpression createNotInFilter(Expression left, List elements)
-    {
-
-        if (!(left instanceof PropertyExpression))
-        {
-            throw new RuntimeException("Expected a property for In expression, got: " + left);
-        }
-
-        return UnaryExpression.createInExpression((PropertyExpression) left, elements, true);
-
-    }
-
-    public static BooleanExpression createIsNull(Expression left)
-    {
-        return ComparisonExpression.doCreateEqual(left, ConstantExpression.NULL);
-    }
-
-    public static BooleanExpression createIsNotNull(Expression left)
-    {
-        return UnaryExpression.createNOT(ComparisonExpression.doCreateEqual(left, ConstantExpression.NULL));
-    }
-
-    public static BooleanExpression createNotEqual(Expression left, Expression right)
-    {
-        return UnaryExpression.createNOT(ComparisonExpression.createEqual(left, right));
-    }
-
-    public static BooleanExpression createEqual(Expression left, Expression right)
-    {
-        ComparisonExpression.checkEqualOperand(left);
-        ComparisonExpression.checkEqualOperand(right);
-        ComparisonExpression.checkEqualOperandCompatability(left, right);
-
-        return ComparisonExpression.doCreateEqual(left, right);
-    }
-
-    private static BooleanExpression doCreateEqual(Expression left, Expression right)
-    {
-        return new ComparisonExpression(left, right)
-            {
-
-                public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-                {
-                    Object lv = left.evaluate(message);
-                    Object rv = right.evaluate(message);
-
-                    // Iff one of the values is null
-                    if ((lv == null) ^ (rv == null))
-                    {
-                        return Boolean.FALSE;
-                    }
-
-                    if ((lv == rv) || lv.equals(rv))
-                    {
-                        return Boolean.TRUE;
-                    }
-
-                    if ((lv instanceof Comparable) && (rv instanceof Comparable))
-                    {
-                        return compare((Comparable) lv, (Comparable) rv);
-                    }
-
-                    return Boolean.FALSE;
-                }
-
-                protected boolean asBoolean(int answer)
-                {
-                    return answer == 0;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "=";
-                }
-            };
-    }
-
-    public static BooleanExpression createGreaterThan(final Expression left, final Expression right)
-    {
-        ComparisonExpression.checkLessThanOperand(left);
-        ComparisonExpression.checkLessThanOperand(right);
-
-        return new ComparisonExpression(left, right)
-            {
-                protected boolean asBoolean(int answer)
-                {
-                    return answer > 0;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return ">";
-                }
-            };
-    }
-
-    public static BooleanExpression createGreaterThanEqual(final Expression left, final Expression right)
-    {
-        ComparisonExpression.checkLessThanOperand(left);
-        ComparisonExpression.checkLessThanOperand(right);
-
-        return new ComparisonExpression(left, right)
-            {
-                protected boolean asBoolean(int answer)
-                {
-                    return answer >= 0;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return ">=";
-                }
-            };
-    }
-
-    public static BooleanExpression createLessThan(final Expression left, final Expression right)
-    {
-        ComparisonExpression.checkLessThanOperand(left);
-        ComparisonExpression.checkLessThanOperand(right);
-
-        return new ComparisonExpression(left, right)
-            {
-
-                protected boolean asBoolean(int answer)
-                {
-                    return answer < 0;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "<";
-                }
-
-            };
-    }
-
-    public static BooleanExpression createLessThanEqual(final Expression left, final Expression right)
-    {
-        ComparisonExpression.checkLessThanOperand(left);
-        ComparisonExpression.checkLessThanOperand(right);
-
-        return new ComparisonExpression(left, right)
-            {
-
-                protected boolean asBoolean(int answer)
-                {
-                    return answer <= 0;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "<=";
-                }
-            };
-    }
-
-    /**
-     * Only Numeric expressions can be used in >, >=, < or <= expressions.s
-     *
-     * @param expr
-     */
-    public static void checkLessThanOperand(Expression expr)
-    {
-        if (expr instanceof ConstantExpression)
-        {
-            Object value = ((ConstantExpression) expr).getValue();
-            if (value instanceof Number)
-            {
-                return;
-            }
-
-            // Else it's boolean or a String..
-            throw new RuntimeException("Value '" + expr + "' cannot be compared.");
-        }
-
-        if (expr instanceof BooleanExpression)
-        {
-            throw new RuntimeException("Value '" + expr + "' cannot be compared.");
-        }
-    }
-
-    /**
-     * Validates that the expression can be used in == or <> expression.
-     * Cannot not be NULL TRUE or FALSE litterals.
-     *
-     * @param expr
-     */
-    public static void checkEqualOperand(Expression expr)
-    {
-        if (expr instanceof ConstantExpression)
-        {
-            Object value = ((ConstantExpression) expr).getValue();
-            if (value == null)
-            {
-                throw new RuntimeException("'" + expr + "' cannot be compared.");
-            }
-        }
-    }
-
-    /**
-     *
-     * @param left
-     * @param right
-     */
-    private static void checkEqualOperandCompatability(Expression left, Expression right)
-    {
-        if ((left instanceof ConstantExpression) && (right instanceof ConstantExpression))
-        {
-            if ((left instanceof BooleanExpression) && !(right instanceof BooleanExpression))
-            {
-                throw new RuntimeException("'" + left + "' cannot be compared with '" + right + "'");
-            }
-        }
-    }
-
-    /**
-     * @param left
-     * @param right
-     */
-    public ComparisonExpression(Expression left, Expression right)
-    {
-        super(left, right);
-    }
-
-    public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-    {
-        Comparable lv = (Comparable) left.evaluate(message);
-        if (lv == null)
-        {
-            return null;
-        }
-
-        Comparable rv = (Comparable) right.evaluate(message);
-        if (rv == null)
-        {
-            return null;
-        }
-
-        return compare(lv, rv);
-    }
-
-    protected Boolean compare(Comparable lv, Comparable rv)
-    {
-        Class lc = lv.getClass();
-        Class rc = rv.getClass();
-        // If the the objects are not of the same type,
-        // try to convert up to allow the comparison.
-        if (lc != rc)
-        {
-            if (lc == Byte.class)
-            {
-                if (rc == Short.class)
-                {
-                    lv = new Short(((Number) lv).shortValue());
-                }
-                else if (rc == Integer.class)
-                {
-                    lv = new Integer(((Number) lv).intValue());
-                }
-                else if (rc == Long.class)
-                {
-                    lv = new Long(((Number) lv).longValue());
-                }
-                else if (rc == Float.class)
-                {
-                    lv = new Float(((Number) lv).floatValue());
-                }
-                else if (rc == Double.class)
-                {
-                    lv = new Double(((Number) lv).doubleValue());
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-            }
-            else if (lc == Short.class)
-            {
-                if (rc == Integer.class)
-                {
-                    lv = new Integer(((Number) lv).intValue());
-                }
-                else if (rc == Long.class)
-                {
-                    lv = new Long(((Number) lv).longValue());
-                }
-                else if (rc == Float.class)
-                {
-                    lv = new Float(((Number) lv).floatValue());
-                }
-                else if (rc == Double.class)
-                {
-                    lv = new Double(((Number) lv).doubleValue());
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-            }
-            else if (lc == Integer.class)
-            {
-                if (rc == Long.class)
-                {
-                    lv = new Long(((Number) lv).longValue());
-                }
-                else if (rc == Float.class)
-                {
-                    lv = new Float(((Number) lv).floatValue());
-                }
-                else if (rc == Double.class)
-                {
-                    lv = new Double(((Number) lv).doubleValue());
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-            }
-            else if (lc == Long.class)
-            {
-                if (rc == Integer.class)
-                {
-                    rv = new Long(((Number) rv).longValue());
-                }
-                else if (rc == Float.class)
-                {
-                    lv = new Float(((Number) lv).floatValue());
-                }
-                else if (rc == Double.class)
-                {
-                    lv = new Double(((Number) lv).doubleValue());
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-            }
-            else if (lc == Float.class)
-            {
-                if (rc == Integer.class)
-                {
-                    rv = new Float(((Number) rv).floatValue());
-                }
-                else if (rc == Long.class)
-                {
-                    rv = new Float(((Number) rv).floatValue());
-                }
-                else if (rc == Double.class)
-                {
-                    lv = new Double(((Number) lv).doubleValue());
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-            }
-            else if (lc == Double.class)
-            {
-                if (rc == Integer.class)
-                {
-                    rv = new Double(((Number) rv).doubleValue());
-                }
-                else if (rc == Long.class)
-                {
-                    rv = new Double(((Number) rv).doubleValue());
-                }
-                else if (rc == Float.class)
-                {
-                    rv = new Float(((Number) rv).doubleValue());
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-            }
-            else
-            {
-                return Boolean.FALSE;
-            }
-        }
-
-        return asBoolean(lv.compareTo(rv)) ? Boolean.TRUE : Boolean.FALSE;
-    }
-
-    protected abstract boolean asBoolean(int answer);
-
-    public boolean matches(AbstractJMSMessage message) throws AMQInternalException
-    {
-        Object object = evaluate(message);
-
-        return (object != null) && (object == Boolean.TRUE);
-    }
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/ConstantExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/ConstantExpression.java
deleted file mode 100644
index 3874d13..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/ConstantExpression.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import java.math.BigDecimal;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-/**
- * Represents a constant expression
- */
-public class ConstantExpression implements Expression
-{
-
-    static class BooleanConstantExpression extends ConstantExpression implements BooleanExpression
-    {
-        public BooleanConstantExpression(Object value)
-        {
-            super(value);
-        }
-
-        public boolean matches(AbstractJMSMessage message) throws AMQInternalException
-        {
-            Object object = evaluate(message);
-
-            return (object != null) && (object == Boolean.TRUE);
-        }
-    }
-
-    public static final BooleanConstantExpression NULL = new BooleanConstantExpression(null);
-    public static final BooleanConstantExpression TRUE = new BooleanConstantExpression(Boolean.TRUE);
-    public static final BooleanConstantExpression FALSE = new BooleanConstantExpression(Boolean.FALSE);
-
-    private Object value;
-
-    public static ConstantExpression createFromDecimal(String text)
-    {
-
-        // Strip off the 'l' or 'L' if needed.
-        if (text.endsWith("l") || text.endsWith("L"))
-        {
-            text = text.substring(0, text.length() - 1);
-        }
-
-        Number value;
-        try
-        {
-            value = new Long(text);
-        }
-        catch (NumberFormatException e)
-        {
-            // The number may be too big to fit in a long.
-            value = new BigDecimal(text);
-        }
-
-        long l = value.longValue();
-        if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE))
-        {
-            value = new Integer(value.intValue());
-        }
-
-        return new ConstantExpression(value);
-    }
-
-    public static ConstantExpression createFromHex(String text)
-    {
-        Number value = new Long(Long.parseLong(text.substring(2), 16));
-        long l = value.longValue();
-        if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE))
-        {
-            value = new Integer(value.intValue());
-        }
-
-        return new ConstantExpression(value);
-    }
-
-    public static ConstantExpression createFromOctal(String text)
-    {
-        Number value = new Long(Long.parseLong(text, 8));
-        long l = value.longValue();
-        if ((Integer.MIN_VALUE <= l) && (l <= Integer.MAX_VALUE))
-        {
-            value = new Integer(value.intValue());
-        }
-
-        return new ConstantExpression(value);
-    }
-
-    public static ConstantExpression createFloat(String text)
-    {
-        Number value = new Double(text);
-
-        return new ConstantExpression(value);
-    }
-
-    public ConstantExpression(Object value)
-    {
-        this.value = value;
-    }
-
-    public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-    {
-        return value;
-    }
-
-    public Object getValue()
-    {
-        return value;
-    }
-
-    /**
-     * @see Object#toString()
-     */
-    public String toString()
-    {
-        if (value == null)
-        {
-            return "NULL";
-        }
-
-        if (value instanceof Boolean)
-        {
-            return ((Boolean) value).booleanValue() ? "TRUE" : "FALSE";
-        }
-
-        if (value instanceof String)
-        {
-            return ConstantExpression.encodeString((String) value);
-        }
-
-        return value.toString();
-    }
-
-    /**
-     * TODO: more efficient hashCode()
-     *
-     * @see Object#hashCode()
-     */
-    public int hashCode()
-    {
-        return toString().hashCode();
-    }
-
-    /**
-     * TODO: more efficient hashCode()
-     *
-     * @see Object#equals(Object)
-     */
-    public boolean equals(Object o)
-    {
-
-        if ((o == null) || !this.getClass().equals(o.getClass()))
-        {
-            return false;
-        }
-
-        return toString().equals(o.toString());
-
-    }
-
-    /**
-     * Encodes the value of string so that it looks like it would look like
-     * when it was provided in a selector.
-     *
-     * @param s
-     * @return
-     */
-    public static String encodeString(String s)
-    {
-        StringBuffer b = new StringBuffer();
-        b.append('\'');
-        for (int i = 0; i < s.length(); i++)
-        {
-            char c = s.charAt(i);
-            if (c == '\'')
-            {
-                b.append(c);
-            }
-
-            b.append(c);
-        }
-
-        b.append('\'');
-
-        return b.toString();
-    }
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/Expression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/Expression.java
deleted file mode 100644
index 8208f49..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/Expression.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-
-/**
- * Represents an expression
- */
-public interface Expression
-{
-    /**
-     * @param message The message to evaluate
-     * @return the value of this expression
-     * @throws AMQInternalException 
-     */
-    public Object evaluate(AbstractJMSMessage message) throws AMQInternalException;
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java
deleted file mode 100644
index a1b4aff..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/JMSSelectorFilter.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-import org.apache.qpid.filter.selector.SelectorParser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-public class JMSSelectorFilter implements MessageFilter
-{
-    private static final Logger _logger = LoggerFactory.getLogger(JMSSelectorFilter.class);
-
-    private final String _selector;
-    private final BooleanExpression _matcher;
-
-    public JMSSelectorFilter(String selector) throws AMQInternalException
-    {
-        if (selector == null || "".equals(selector))
-        {
-            throw new IllegalArgumentException("Cannot create a JMSSelectorFilter with a null or empty selector string");
-        }
-        _selector = selector;
-        if (_logger.isDebugEnabled())
-        {
-            _logger.debug("Created JMSSelectorFilter with selector:" + _selector);
-        }
-        _matcher = new SelectorParser().parse(selector);
-    }
-
-    public boolean matches(AbstractJMSMessage message)
-    {
-        try
-        {
-            boolean match = _matcher.matches(message);
-            if (_logger.isDebugEnabled())
-            {
-                _logger.debug(message + " match(" + match + ") selector(" + _selector + "): " + _selector);
-            }
-            return match;
-        }
-        catch (AMQInternalException e)
-        {
-            _logger.warn("Caught exception when evaluating message selector for message  " + message, e);
-        }
-        return false;
-    }
-
-    public String getSelector()
-    {
-        return _selector;
-    }
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/LogicExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/LogicExpression.java
deleted file mode 100644
index 7ef85cb..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/LogicExpression.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-
-/**
- * A filter performing a comparison of two objects
- */
-public abstract class LogicExpression extends BinaryExpression implements BooleanExpression
-{
-
-    public static BooleanExpression createOR(BooleanExpression lvalue, BooleanExpression rvalue)
-    {
-        return new LogicExpression(lvalue, rvalue)
-            {
-
-                public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-                {
-
-                    Boolean lv = (Boolean) left.evaluate(message);
-                    // Can we do an OR shortcut??
-                    if ((lv != null) && lv.booleanValue())
-                    {
-                        return Boolean.TRUE;
-                    }
-
-                    Boolean rv = (Boolean) right.evaluate(message);
-
-                    return (rv == null) ? null : rv;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "OR";
-                }
-            };
-    }
-
-    public static BooleanExpression createAND(BooleanExpression lvalue, BooleanExpression rvalue)
-    {
-        return new LogicExpression(lvalue, rvalue)
-            {
-
-                public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-                {
-
-                    Boolean lv = (Boolean) left.evaluate(message);
-
-                    // Can we do an AND shortcut??
-                    if (lv == null)
-                    {
-                        return null;
-                    }
-
-                    if (!lv.booleanValue())
-                    {
-                        return Boolean.FALSE;
-                    }
-
-                    Boolean rv = (Boolean) right.evaluate(message);
-
-                    return (rv == null) ? null : rv;
-                }
-
-                public String getExpressionSymbol()
-                {
-                    return "AND";
-                }
-            };
-    }
-
-    /**
-     * @param left
-     * @param right
-     */
-    public LogicExpression(BooleanExpression left, BooleanExpression right)
-    {
-        super(left, right);
-    }
-
-    public abstract Object evaluate(AbstractJMSMessage message) throws AMQInternalException;
-
-    public boolean matches(AbstractJMSMessage message) throws AMQInternalException
-    {
-        Object object = evaluate(message);
-
-        return (object != null) && (object == Boolean.TRUE);
-    }
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
deleted file mode 100644
index 574a1b3..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/PropertyExpression.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import java.util.HashMap;
-
-import javax.jms.DeliveryMode;
-import javax.jms.JMSException;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Represents a property  expression
- */
-public class PropertyExpression implements Expression
-{
-    // Constants - defined the same as JMS
-    private static enum JMSDeliveryMode { NON_PERSISTENT, PERSISTENT }
-    private static final int DEFAULT_PRIORITY = 4;
-
-    private static final Logger _logger = LoggerFactory.getLogger(PropertyExpression.class);
-
-    private static final HashMap<String, Expression> JMS_PROPERTY_EXPRESSIONS = new HashMap<String, Expression>();
-
-    static
-    {
-        JMS_PROPERTY_EXPRESSIONS.put("JMSDestination", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-                                             //TODO
-                                             return null;
-                                         }
-                                     });
-        JMS_PROPERTY_EXPRESSIONS.put("JMSReplyTo", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-                                             return message.getReplyToString();
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSType", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-                                             try
-                                             {
-                                                 return message.getJMSType();
-                                             }
-                                             catch (JMSException e)
-                                             {
-                                                 _logger.warn("Error evaluating property", e);
-
-                                                 return null;
-                                             }
-
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSDeliveryMode", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-
-                                             JMSDeliveryMode mode = JMSDeliveryMode.NON_PERSISTENT;
-                                             try
-                                             {
-                                                 mode = message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT ?
-                                                         JMSDeliveryMode.PERSISTENT : JMSDeliveryMode.NON_PERSISTENT;
-
-                                                 if (_logger.isDebugEnabled())
-                                                 {
-                                                     _logger.debug("JMSDeliveryMode is :" + mode);
-                                                 }
-                                             }
-                                             catch (JMSException e)
-                                             {
-                                                 _logger.warn("Error evaluating property",e);
-                                             }
-
-                                             return mode.toString();
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSPriority", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-                                             try
-                                             {
-                                                 return message.getJMSPriority();
-                                             }
-                                             catch (Exception e)
-                                             {
-                                                 _logger.warn("Error evaluating property",e);
-                                             }
-
-                                             return DEFAULT_PRIORITY;
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("AMQMessageID", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-
-                                             try
-                                             {
-                                                 return message.getJMSMessageID();
-                                             }
-                                             catch (JMSException e)
-                                             {
-                                                 _logger.warn("Error evaluating property",e);
-
-                                                 return null;
-                                             }
-
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSTimestamp", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-                                             try
-                                             {
-                                                 return message.getJMSTimestamp();
-                                             }
-                                             catch (Exception e)
-                                             {
-                                                 _logger.warn("Error evaluating property",e);
-
-                                                 return null;
-                                             }
-
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSCorrelationID", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-
-                                             try
-                                             {
-                                                 return message.getJMSCorrelationID();
-                                             }
-                                             catch (JMSException e)
-                                             {
-                                                 _logger.warn("Error evaluating property",e);
-
-                                                 return null;
-                                             }
-
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSExpiration", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-
-                                             try
-                                             {
-                                                 return message.getJMSExpiration();
-                                             }
-                                             catch (JMSException e)
-                                             {
-                                                 _logger.warn("Error evaluating property",e);
-                                                 return null;
-                                             }
-
-                                         }
-                                     });
-
-        JMS_PROPERTY_EXPRESSIONS.put("JMSRedelivered", new Expression()
-                                     {
-                                         public Object evaluate(AbstractJMSMessage message)
-                                         {
-                                             try
-                                             {
-                                                 return message.getJMSRedelivered();
-                                             }
-                                             catch (JMSException e)
-                                             {
-                                                _logger.warn("Error evaluating property",e);
-                                                 return null;
-                                             }
-                                         }
-                                     });
-        
-        JMS_PROPERTY_EXPRESSIONS.put("JMSMessageID", new Expression()
-                                    {
-                                        public Object evaluate(AbstractJMSMessage message)
-                                        {
-                                            try
-                                            {
-                                                return message.getJMSMessageID();
-                                            }
-                                            catch (Exception e)
-                                            {
-                                                _logger.warn("Error evaluating property",e);
-                            
-                                                return null;
-                                            }
-                            
-                                        }
-                                    });
-
-    }
-
-    private final String name;
-    private final Expression jmsPropertyExpression;
-
-    public PropertyExpression(String name)
-    {
-        this.name = name;
-        jmsPropertyExpression = JMS_PROPERTY_EXPRESSIONS.get(name);
-    }
-
-    public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-    {
-
-        if (jmsPropertyExpression != null)
-        {
-            return jmsPropertyExpression.evaluate(message);
-        }
-        else
-        {
-
-            try
-            {
-
-                if (_logger.isDebugEnabled())
-                {
-                    _logger.debug("Looking up property:" + name);
-                    _logger.debug("Properties are:" + message.getPropertyNames());
-                }
-                return message.getObjectProperty(name);
-            }
-            catch(JMSException e)
-            {
-                throw new AMQInternalException("Exception evaluating properties for filter", e);
-            }
-        }
-    }
-
-    public String getName()
-    {
-        return name;
-    }
-
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        return name;
-    }
-
-    /**
-     * @see java.lang.Object#hashCode()
-     */
-    public int hashCode()
-    {
-        return name.hashCode();
-    }
-
-    /**
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    public boolean equals(Object o)
-    {
-        if ((o == null) || !this.getClass().equals(o.getClass()))
-        {
-            return false;
-        }
-        return name.equals(((PropertyExpression) o).name);
-    }
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/UnaryExpression.java b/qpid/java/client/src/main/java/org/apache/qpid/filter/UnaryExpression.java
deleted file mode 100644
index 0fc3382..0000000
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/UnaryExpression.java
+++ /dev/null
@@ -1,321 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- * 
- *   http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.filter;
-
-import java.math.BigDecimal;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-/**
- * An expression which performs an operation on two expression values
- */
-public abstract class UnaryExpression implements Expression
-{
-
-    private static final BigDecimal BD_LONG_MIN_VALUE = BigDecimal.valueOf(Long.MIN_VALUE);
-    protected Expression right;
-
-    public static Expression createNegate(Expression left)
-    {
-        return new UnaryExpression(left)
-        {
-            public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-            {
-                Object rvalue = right.evaluate(message);
-                if (rvalue == null)
-                {
-                    return null;
-                }
-
-                if (rvalue instanceof Number)
-                {
-                    return UnaryExpression.negate((Number) rvalue);
-                }
-
-                return null;
-            }
-
-            public String getExpressionSymbol()
-            {
-                return "-";
-            }
-        };
-    }
-
-    public static BooleanExpression createInExpression(PropertyExpression right, List elements, final boolean not)
-    {
-
-        // Use a HashSet if there are many elements.
-        Collection t;
-        if (elements.size() == 0)
-        {
-            t = null;
-        }
-        else if (elements.size() < 5)
-        {
-            t = elements;
-        }
-        else
-        {
-            t = new HashSet(elements);
-        }
-
-        final Collection inList = t;
-
-        return new BooleanUnaryExpression(right)
-        {
-            public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-            {
-
-                Object rvalue = right.evaluate(message);
-                if (rvalue == null)
-                {
-                    return null;
-                }
-
-                if (rvalue.getClass() != String.class)
-                {
-                    return null;
-                }
-
-                if (((inList != null) && inList.contains(rvalue)) ^ not)
-                {
-                    return Boolean.TRUE;
-                }
-                else
-                {
-                    return Boolean.FALSE;
-                }
-
-            }
-
-            public String toString()
-            {
-                StringBuffer answer = new StringBuffer();
-                answer.append(right);
-                answer.append(" ");
-                answer.append(getExpressionSymbol());
-                answer.append(" ( ");
-
-                int count = 0;
-                for (Iterator i = inList.iterator(); i.hasNext();)
-                {
-                    Object o = (Object) i.next();
-                    if (count != 0)
-                    {
-                        answer.append(", ");
-                    }
-
-                    answer.append(o);
-                    count++;
-                }
-
-                answer.append(" )");
-
-                return answer.toString();
-            }
-
-            public String getExpressionSymbol()
-            {
-                if (not)
-                {
-                    return "NOT IN";
-                }
-                else
-                {
-                    return "IN";
-                }
-            }
-        };
-    }
-
-    abstract static class BooleanUnaryExpression extends UnaryExpression implements BooleanExpression
-    {
-        public BooleanUnaryExpression(Expression left)
-        {
-            super(left);
-        }
-
-        public boolean matches(AbstractJMSMessage message) throws AMQInternalException
-        {
-            Object object = evaluate(message);
-
-            return (object != null) && (object == Boolean.TRUE);
-        }
-    }
-
-    ;
-
-    public static BooleanExpression createNOT(BooleanExpression left)
-    {
-        return new BooleanUnaryExpression(left)
-        {
-            public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-            {
-                Boolean lvalue = (Boolean) right.evaluate(message);
-                if (lvalue == null)
-                {
-                    return null;
-                }
-
-                return lvalue.booleanValue() ? Boolean.FALSE : Boolean.TRUE;
-            }
-
-            public String getExpressionSymbol()
-            {
-                return "NOT";
-            }
-        };
-    }
-    public static BooleanExpression createBooleanCast(Expression left)
-    {
-        return new BooleanUnaryExpression(left)
-        {
-            public Object evaluate(AbstractJMSMessage message) throws AMQInternalException
-            {
-                Object rvalue = right.evaluate(message);
-                if (rvalue == null)
-                {
-                    return null;
-                }
-
-                if (!rvalue.getClass().equals(Boolean.class))
-                {
-                    return Boolean.FALSE;
-                }
-
-                return ((Boolean) rvalue).booleanValue() ? Boolean.TRUE : Boolean.FALSE;
-            }
-
-            public String toString()
-            {
-                return right.toString();
-            }
-
-            public String getExpressionSymbol()
-            {
-                return "";
-            }
-        };
-    }
-
-    private static Number negate(Number left)
-    {
-        Class clazz = left.getClass();
-        if (clazz == Integer.class)
-        {
-            return new Integer(-left.intValue());
-        }
-        else if (clazz == Long.class)
-        {
-            return new Long(-left.longValue());
-        }
-        else if (clazz == Float.class)
-        {
-            return new Float(-left.floatValue());
-        }
-        else if (clazz == Double.class)
-        {
-            return new Double(-left.doubleValue());
-        }
-        else if (clazz == BigDecimal.class)
-        {
-            // We ussually get a big deciamal when we have Long.MIN_VALUE constant in the
-            // Selector.  Long.MIN_VALUE is too big to store in a Long as a positive so we store it
-            // as a Big decimal.  But it gets Negated right away.. to here we try to covert it back
-            // to a Long.
-            BigDecimal bd = (BigDecimal) left;
-            bd = bd.negate();
-
-            if (UnaryExpression.BD_LONG_MIN_VALUE.compareTo(bd) == 0)
-            {
-                return new Long(Long.MIN_VALUE);
-            }
-
-            return bd;
-        }
-        else
-        {
-            throw new RuntimeException("Don't know how to negate: " + left);
-        }
-    }
-
-    public UnaryExpression(Expression left)
-    {
-        this.right = left;
-    }
-
-    public Expression getRight()
-    {
-        return right;
-    }
-
-    public void setRight(Expression expression)
-    {
-        right = expression;
-    }
-
-    /**
-     * @see Object#toString()
-     */
-    public String toString()
-    {
-        return "(" + getExpressionSymbol() + " " + right.toString() + ")";
-    }
-
-    /**
-     * TODO: more efficient hashCode()
-     *
-     * @see Object#hashCode()
-     */
-    public int hashCode()
-    {
-        return toString().hashCode();
-    }
-
-    /**
-     * TODO: more efficient hashCode()
-     *
-     * @see Object#equals(Object)
-     */
-    public boolean equals(Object o)
-    {
-
-        if ((o == null) || !this.getClass().equals(o.getClass()))
-        {
-            return false;
-        }
-
-        return toString().equals(o.toString());
-
-    }
-
-    /**
-     * Returns the symbol that represents this binary expression.  For example, addition is
-     * represented by "+"
-     *
-     * @return
-     */
-    public abstract String getExpressionSymbol();
-
-}
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java b/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
index 10fd8d2..2f1eda6 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
+++ b/qpid/java/client/src/main/java/org/apache/qpid/nclient/util/MessagePartListenerAdapter.java
@@ -49,19 +49,9 @@
     {
         _currentMsg = new ByteBufferMessage(xfr.getId());
 
-        for (Struct st : xfr.getHeader().getStructs())
-        {
-            if(st instanceof DeliveryProperties)
-            {
-                _currentMsg.setDeliveryProperties((DeliveryProperties)st);
-
-            }
-            else if(st instanceof MessageProperties)
-            {
-                _currentMsg.setMessageProperties((MessageProperties)st);
-            }
-
-        }
+        Header header = xfr.getHeader();
+        _currentMsg.setDeliveryProperties(header.getDeliveryProperties());
+        _currentMsg.setMessageProperties(header.getMessageProperties());
 
 
         ByteBuffer body = xfr.getBody();
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java
index f53fa8d..1889577 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQSession_0_10Test.java
@@ -588,7 +588,7 @@
         }
         boolean isTransacted = acknowledgeMode == javax.jms.Session.SESSION_TRANSACTED ? true : false;
         AMQSession_0_10 session = new AMQSession_0_10(createConnection(throwException), amqConnection, 1, isTransacted, acknowledgeMode,
-                 1, 1, "test");
+                 0, 0, "test");
         return session;
     }
 
@@ -600,7 +600,6 @@
         connection.setSessionFactory(new SessionFactory()
         {
 
-            @Override
             public Session newSession(Connection conn, Binary name, long expiry)
             {
                 return new MockSession(conn, new SessionDelegate(), name, expiry, throwException);
@@ -611,7 +610,6 @@
 
     private final class MockMessageListener implements MessageListener
     {
-        @Override
         public void onMessage(Message arg0)
         {
         }
@@ -710,23 +708,19 @@
     {
         private List<ProtocolEvent> _sendEvents = new ArrayList<ProtocolEvent>();
 
-        @Override
         public void setIdleTimeout(int i)
         {
         }
 
-        @Override
         public void send(ProtocolEvent msg)
         {
             _sendEvents.add(msg);
         }
 
-        @Override
         public void flush()
         {
         }
 
-        @Override
         public void close()
         {
         }
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java b/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java
index d8d94ba..02089cc 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/client/BasicMessageConsumer_0_8_Test.java
@@ -46,8 +46,9 @@
         AMQBindingURL burl = new AMQBindingURL(url);
         AMQDestination queue = new AMQQueue(burl);
 
-        AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn);
-        BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
+        TestAMQSession testSession = new TestAMQSession(conn);
+        BasicMessageConsumer_0_8 consumer =
+                new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
 
         assertEquals("Reject behaviour was was not as expected", RejectBehaviour.SERVER, consumer.getRejectBehaviour());
     }
@@ -65,8 +66,9 @@
         final AMQBindingURL burl = new AMQBindingURL(url);
         final AMQDestination queue = new AMQQueue(burl);
 
-        final AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn);
-        final BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
+        final TestAMQSession testSession = new TestAMQSession(conn);
+        final BasicMessageConsumer_0_8 consumer =
+                new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
 
         assertEquals("Reject behaviour was was not as expected", RejectBehaviour.NORMAL, consumer.getRejectBehaviour());
     }
@@ -90,8 +92,9 @@
 
         assertNull("Reject behaviour should have been null", queue.getRejectBehaviour());
 
-        AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8> testSession = new TestAMQSession(conn);
-        BasicMessageConsumer_0_8 consumer = new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
+        TestAMQSession testSession = new TestAMQSession(conn);
+        BasicMessageConsumer_0_8 consumer =
+                new BasicMessageConsumer_0_8(0, conn, queue, "", false, null, testSession, null, null, 10, 5, false, Session.SESSION_TRANSACTED, false, false);
 
         assertEquals("Reject behaviour was was not as expected", RejectBehaviour.NORMAL, consumer.getRejectBehaviour());
     }
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/filter/JMSSelectorFilterTest.java b/qpid/java/client/src/test/java/org/apache/qpid/filter/JMSSelectorFilterTest.java
deleted file mode 100644
index d4d8ea4..0000000
--- a/qpid/java/client/src/test/java/org/apache/qpid/filter/JMSSelectorFilterTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.filter;
-
-import junit.framework.TestCase;
-
-import org.apache.qpid.AMQInternalException;
-import org.apache.qpid.client.message.JMSTextMessage;
-import org.apache.qpid.client.message.TestMessageHelper;
-
-public class JMSSelectorFilterTest extends TestCase
-{
-
-    public void testEmptySelectorFilter() throws Exception
-    {
-        try
-        {
-            new JMSSelectorFilter("");
-            fail("Should not be able to create a JMSSelectorFilter with an empty selector");
-        }
-        catch (IllegalArgumentException iae)
-        {
-            // pass
-        }
-    }
-
-    public void testNullSelectorFilter() throws Exception
-    {
-        try
-        {
-            new JMSSelectorFilter(null);
-            fail("Should not be able to create a JMSSelectorFilter with a null selector");
-        }
-        catch (IllegalArgumentException iae)
-        {
-            // pass
-        }
-    }
-
-    public void testInvalidSelectorFilter() throws Exception
-    {
-        try
-        {
-            new JMSSelectorFilter("$%^");
-            fail("Unparsable selector so expected AMQInternalException to be thrown");
-        }
-        catch (AMQInternalException amqie)
-        {
-            // pass
-        }
-    }
-
-    public void testSimpleSelectorFilter() throws Exception
-    {
-        MessageFilter simpleSelectorFilter = new JMSSelectorFilter("select=5");
-
-        assertNotNull("Filter object is null", simpleSelectorFilter);
-        assertNotNull("Selector string is null", simpleSelectorFilter.getSelector());
-        assertEquals("Unexpected selector", "select=5", simpleSelectorFilter.getSelector());
-        assertTrue("Filter object is invalid", simpleSelectorFilter != null);
-
-        final JMSTextMessage message = TestMessageHelper.newJMSTextMessage();
-
-        message.setIntProperty("select", 4);
-        assertFalse("Selector did match when not expected", simpleSelectorFilter.matches(message));
-        message.setIntProperty("select", 5);
-        assertTrue("Selector didnt match when expected", simpleSelectorFilter.matches(message));
-        message.setIntProperty("select", 6);
-        assertFalse("Selector did match when not expected", simpleSelectorFilter.matches(message));
-    }
-
-    public void testFailedMatchingFilter() throws Exception
-    {
-        MessageFilter simpleSelectorFilter = new JMSSelectorFilter("select>4");
-
-        assertNotNull("Filter object is null", simpleSelectorFilter);
-        assertNotNull("Selector string is null", simpleSelectorFilter.getSelector());
-        assertEquals("Unexpected selector", "select>4", simpleSelectorFilter.getSelector());
-        assertTrue("Filter object is invalid", simpleSelectorFilter != null);
-
-        final JMSTextMessage message = TestMessageHelper.newJMSTextMessage();
-
-        message.setStringProperty("select", "5");
-        assertFalse("Selector matched when not expected", simpleSelectorFilter.matches(message));
-        message.setStringProperty("select", "elephant");
-        assertFalse("Selector matched when not expected", simpleSelectorFilter.matches(message));
-        message.setBooleanProperty("select", false);
-        assertFalse("Selector matched when not expected", simpleSelectorFilter.matches(message));
-    }
-}
diff --git a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
index 06d0f4a..4c3e9c2 100644
--- a/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
+++ b/qpid/java/client/src/test/java/org/apache/qpid/test/unit/message/TestAMQSession.java
@@ -29,12 +29,7 @@
 import javax.jms.TopicSubscriber;
 
 import org.apache.qpid.AMQException;
-import org.apache.qpid.client.AMQConnection;
-import org.apache.qpid.client.AMQDestination;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.BasicMessageConsumer_0_8;
-import org.apache.qpid.client.BasicMessageProducer_0_8;
-import org.apache.qpid.client.MockAMQConnection;
+import org.apache.qpid.client.*;
 import org.apache.qpid.client.failover.FailoverException;
 import org.apache.qpid.client.message.AMQMessageDelegateFactory;
 import org.apache.qpid.client.protocol.AMQProtocolHandler;
@@ -42,7 +37,7 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 
-public class TestAMQSession extends AMQSession<BasicMessageConsumer_0_8, BasicMessageProducer_0_8>
+public class TestAMQSession extends AMQSession_0_8
 {
 
     public TestAMQSession(AMQConnection connection)
@@ -92,7 +87,7 @@
         return null;
     }
 
-    protected void sendRecover() throws AMQException, FailoverException
+    public void sendRecover() throws AMQException, FailoverException
     {
 
     }
diff --git a/qpid/java/common.xml b/qpid/java/common.xml
index 26537e7..4e9e2d1 100644
--- a/qpid/java/common.xml
+++ b/qpid/java/common.xml
@@ -61,6 +61,12 @@
   <property name="javac.compiler.args"   value=""/>
 
   <property name="cobertura.dir" value="${project.root}/lib/cobertura" />
+  <property name="cobertura.version" value="1.9.4.1" />
+  <property name="cobertura.download.url"
+            value="http://downloads.sourceforge.net/project/cobertura/cobertura/${cobertura.version}/cobertura-${cobertura.version}-bin.zip" />
+  <property name="cobertura.zip.filename" value="cobertura-${cobertura.version}-bin.zip" />
+  <property name="cobertura.temp.dir" value="${cobertura.dir}"/>
+
   <property name="mllib.dir" value="${project.root}/../python" />
   <property name="findbugs.dir" value="${project.root}/lib/findbugs" />
 
@@ -71,8 +77,8 @@
 
   <path id="cobertura.classpath">
     <fileset dir="${cobertura.dir}">
-        <include name="cobertura.jar" />
-        <include name="lib/**/*.jar" />
+        <include name="cobertura-${cobertura.version}/*.jar" />
+        <include name="cobertura-${cobertura.version}/**/lib/*.jar" />
     </fileset>
   </path>
 
@@ -192,6 +198,22 @@
     <taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
   </target>
 
+  <!--download Cobertura jar and expand-->
+  <target name="download-cobertura" description="download Cobertura if not already present" depends="cobertura-check" unless="cobertura.already.exists">
+      <mkdir dir="${cobertura.dir}"/>
+      <echo>Downloading Cobertura ${cobertura.version}</echo>
+      <get src="${cobertura.download.url}" dest="${cobertura.temp.dir}/${cobertura.zip.filename}" usetimestamp="false" />
+      <echo>Extracting Cobertura JAR and dependencies</echo>
+      <unzip src="${cobertura.temp.dir}/${cobertura.zip.filename}" dest="${cobertura.dir}"/>
+      <echo>Cleanup Cobertura Download</echo>
+      <delete file="${cobertura.temp.dir}/${cobertura.zip.filename}"/>
+      <echo>Done</echo>
+  </target>
+
+  <target name="cobertura-check">
+    <available property="cobertura.already.exists" file="${cobertura.dir}/cobertura-${cobertura.version}" type="dir"/>
+  </target>
+
   <target name="findbugs-init">
     <available file="${findbugs.dir}/findbugs-ant.jar" property="findbugs-ant.jar.present"/>
     <fail unless="findbugs-ant.jar.present" message="Please follow the instructions at ${findbugs.dir}/README.txt to configure FindBugs"/>
diff --git a/qpid/java/common/Composite.tpl b/qpid/java/common/Composite.tpl
index 350dd89..2cbd683 100644
--- a/qpid/java/common/Composite.tpl
+++ b/qpid/java/common/Composite.tpl
@@ -245,6 +245,11 @@
         return this;
     }
 
+    public int getBodySize()
+    {
+        return this.body == null ? 0 : this.body.remaining();
+    }
+
     public final ByteBuffer getBody() {
         if (this.body == null)
         {
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
index 69bf73b..1d19653 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
@@ -24,12 +24,7 @@
 import java.nio.ByteBuffer;
 import java.util.*;
 
-import org.apache.qpid.framing.AMQDataBlock;
-import org.apache.qpid.framing.AMQDataBlockDecoder;
-import org.apache.qpid.framing.AMQFrameDecodingException;
-import org.apache.qpid.framing.AMQMethodBodyFactory;
-import org.apache.qpid.framing.AMQProtocolVersionException;
-import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.*;
 import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
 
 /**
@@ -193,24 +188,41 @@
         }
     }
 
+    private static class SimpleDataInputStream extends DataInputStream implements MarkableDataInput
+    {
+        public SimpleDataInputStream(InputStream in)
+        {
+            super(in);
+        }
+
+        public AMQShortString readAMQShortString() throws IOException
+        {
+            return EncodingUtils.readAMQShortString(this);
+        }
+
+    }
+
 
     public ArrayList<AMQDataBlock> decodeBuffer(ByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
     {
 
         // get prior remaining data from accumulator
         ArrayList<AMQDataBlock> dataBlocks = new ArrayList<AMQDataBlock>();
-        DataInputStream msg;
+        MarkableDataInput msg;
 
 
-        ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining());
+        ByteArrayInputStream bais;
+        DataInput di;
         if(!_remainingBufs.isEmpty())
         {
+             bais = new ByteArrayInputStream(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining());
             _remainingBufs.add(bais);
-            msg = new DataInputStream(new RemainingByteArrayInputStream());
+            msg = new SimpleDataInputStream(new RemainingByteArrayInputStream());
         }
         else
         {
-            msg = new DataInputStream(bais);
+            bais = null;
+            msg = new ByteArrayDataInput(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining());
         }
 
         boolean enoughData = true;
@@ -245,11 +257,24 @@
                         iterator.remove();
                     }
                 }
-                if(bais.available()!=0)
+
+                if(bais == null)
                 {
-                    byte[] remaining = new byte[bais.available()];
-                    bais.read(remaining);
-                    _remainingBufs.add(new ByteArrayInputStream(remaining));
+                    if(msg.available()!=0)
+                    {
+                        byte[] remaining = new byte[msg.available()];
+                        msg.read(remaining);
+                        _remainingBufs.add(new ByteArrayInputStream(remaining));
+                    }
+                }
+                else
+                {
+                    if(bais.available()!=0)
+                    {
+                        byte[] remaining = new byte[bais.available()];
+                        bais.read(remaining);
+                        _remainingBufs.add(new ByteArrayInputStream(remaining));
+                    }
                 }
             }
         }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/codec/MarkableDataInput.java b/qpid/java/common/src/main/java/org/apache/qpid/codec/MarkableDataInput.java
new file mode 100644
index 0000000..2a243a8
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/codec/MarkableDataInput.java
@@ -0,0 +1,21 @@
+package org.apache.qpid.codec;
+
+import org.apache.qpid.framing.AMQShortString;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+public interface MarkableDataInput extends DataInput
+{
+    public void mark(int pos);
+    public void reset() throws IOException;
+
+    int available() throws IOException;
+
+    long skip(long i) throws IOException;
+
+    int read(byte[] b) throws IOException;
+
+    public AMQShortString readAMQShortString() throws IOException;
+
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java
index ebdad12..363d9f1 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
 
@@ -36,7 +37,7 @@
      */
     public abstract int getSize();
     
-    public void writePayload(DataOutputStream buffer) throws IOException;
+    public void writePayload(DataOutput buffer) throws IOException;
     
     void handle(final int channelId, final AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException;
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java
index 00c1f5a..e77e594 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.framing;
 
 import java.io.DataInputStream;
+import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
 
@@ -42,6 +43,6 @@
      * Writes the datablock to the specified buffer.
      * @param buffer
      */
-    public abstract void writePayload(DataOutputStream buffer) throws IOException;
+    public abstract void writePayload(DataOutput buffer) throws IOException;
 
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
index 2165cad..b6f2fb1 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.framing;
 
+import org.apache.qpid.codec.MarkableDataInput;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,7 +44,7 @@
     public AMQDataBlockDecoder()
     { }
 
-    public boolean decodable(DataInputStream in) throws AMQFrameDecodingException, IOException
+    public boolean decodable(MarkableDataInput in) throws AMQFrameDecodingException, IOException
     {
         final int remainingAfterAttributes = in.available() - (1 + 2 + 4 + 1);
         // type, channel, body length and end byte
@@ -65,7 +66,7 @@
 
     }
 
-    public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, DataInputStream in)
+    public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, MarkableDataInput in)
             throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
     {
         final byte type = in.readByte();
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java
index 6acf60a..9b5699e 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java
@@ -20,9 +20,10 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.qpid.codec.MarkableDataInput;
+
+import java.io.*;
+import java.io.DataOutput;
 
 public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock
 {
@@ -38,7 +39,7 @@
         _bodyFrame = bodyFrame;
     }
 
-    public AMQFrame(final DataInputStream in, final int channel, final long bodySize, final BodyFactory bodyFactory) throws AMQFrameDecodingException, IOException
+    public AMQFrame(final MarkableDataInput in, final int channel, final long bodySize, final BodyFactory bodyFactory) throws AMQFrameDecodingException, IOException
     {
         this._channel = channel;
         this._bodyFrame = bodyFactory.createBody(in,bodySize);
@@ -55,7 +56,7 @@
     }
 
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
         buffer.writeByte(_bodyFrame.getFrameType());
         EncodingUtils.writeUnsignedShort(buffer, _channel);
@@ -79,7 +80,7 @@
         return "Frame channelId: " + _channel + ", bodyFrame: " + String.valueOf(_bodyFrame);
     }
 
-    public static void writeFrame(DataOutputStream buffer, final int channel, AMQBody body) throws IOException
+    public static void writeFrame(DataOutput buffer, final int channel, AMQBody body) throws IOException
     {
         buffer.writeByte(body.getFrameType());
         EncodingUtils.writeUnsignedShort(buffer, channel);
@@ -89,7 +90,7 @@
 
     }
 
-    public static void writeFrames(DataOutputStream buffer, final int channel, AMQBody body1, AMQBody body2) throws IOException
+    public static void writeFrames(DataOutput buffer, final int channel, AMQBody body1, AMQBody body2) throws IOException
     {
         buffer.writeByte(body1.getFrameType());
         EncodingUtils.writeUnsignedShort(buffer, channel);
@@ -104,7 +105,7 @@
 
     }
 
-    public static void writeFrames(DataOutputStream buffer, final int channel, AMQBody body1, AMQBody body2, AMQBody body3) throws IOException
+    public static void writeFrames(DataOutput buffer, final int channel, AMQBody body1, AMQBody body2, AMQBody body3) throws IOException
     {
         buffer.writeByte(body1.getFrameType());
         EncodingUtils.writeUnsignedShort(buffer, channel);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java
index a076d0e..2170ebf 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java
@@ -25,6 +25,7 @@
 import org.apache.qpid.AMQException;
 import org.apache.qpid.protocol.AMQConstant;
 
+import java.io.DataOutput;
 import java.io.DataOutputStream;
 import java.io.IOException;
 
@@ -45,12 +46,12 @@
     /** @return unsigned short */
     public int getMethod();
 
-    public void writeMethodPayload(DataOutputStream buffer) throws IOException;
+    public void writeMethodPayload(DataOutput buffer) throws IOException;
 
 
     public int getSize();
 
-    public void writePayload(DataOutputStream buffer) throws IOException;
+    public void writePayload(DataOutput buffer) throws IOException;
 
     //public abstract void populateMethodBodyFromBuffer(ByteBuffer buffer) throws AMQFrameDecodingException;
 
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java
index 7fceb08..ec6d662 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java
@@ -20,11 +20,13 @@
  */
 package org.apache.qpid.framing;
 
+import org.apache.qpid.codec.MarkableDataInput;
 import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.IOException;
 
@@ -39,7 +41,7 @@
         _protocolSession = protocolSession;
     }
 
-    public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException
+    public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException
     {
         return _protocolSession.getMethodRegistry().convertToBody(in, bodySize);
     }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
index c73c1df..d6f518b 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
@@ -24,11 +24,12 @@
 import org.apache.qpid.AMQChannelException;
 import org.apache.qpid.AMQConnectionException;
 import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.MarkableDataInput;
 import org.apache.qpid.protocol.AMQConstant;
 import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
 import java.io.IOException;
 
 public abstract class AMQMethodBodyImpl implements AMQMethodBody
@@ -101,7 +102,7 @@
         return 2 + 2 + getBodySize();
     }
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
         EncodingUtils.writeUnsignedShort(buffer, getClazz());
         EncodingUtils.writeUnsignedShort(buffer, getMethod());
@@ -109,14 +110,15 @@
     }
 
 
-    protected byte readByte(DataInputStream buffer) throws IOException
+    protected byte readByte(DataInput buffer) throws IOException
     {
         return buffer.readByte();
     }
 
-    protected AMQShortString readAMQShortString(DataInputStream buffer) throws IOException
+    protected AMQShortString readAMQShortString(MarkableDataInput buffer) throws IOException
     {
-        return EncodingUtils.readAMQShortString(buffer);
+        AMQShortString str = buffer.readAMQShortString();
+        return str == null ? null : str.intern(false);
     }
 
     protected int getSizeOf(AMQShortString string)
@@ -124,27 +126,27 @@
         return EncodingUtils.encodedShortStringLength(string);
     }
 
-    protected void writeByte(DataOutputStream buffer, byte b) throws IOException
+    protected void writeByte(DataOutput buffer, byte b) throws IOException
     {
         buffer.writeByte(b);
     }
 
-    protected void writeAMQShortString(DataOutputStream buffer, AMQShortString string) throws IOException
+    protected void writeAMQShortString(DataOutput buffer, AMQShortString string) throws IOException
     {
         EncodingUtils.writeShortStringBytes(buffer, string);
     }
 
-    protected int readInt(DataInputStream buffer) throws IOException
+    protected int readInt(DataInput buffer) throws IOException
     {
         return buffer.readInt();
     }
 
-    protected void writeInt(DataOutputStream buffer, int i) throws IOException
+    protected void writeInt(DataOutput buffer, int i) throws IOException
     {
         buffer.writeInt(i);
     }
 
-    protected FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException
+    protected FieldTable readFieldTable(DataInput buffer) throws AMQFrameDecodingException, IOException
     {
         return EncodingUtils.readFieldTable(buffer);
     }
@@ -154,17 +156,17 @@
         return EncodingUtils.encodedFieldTableLength(table);  //To change body of created methods use File | Settings | File Templates.
     }
 
-    protected void writeFieldTable(DataOutputStream buffer, FieldTable table) throws IOException
+    protected void writeFieldTable(DataOutput buffer, FieldTable table) throws IOException
     {
         EncodingUtils.writeFieldTableBytes(buffer, table);
     }
 
-    protected long readLong(DataInputStream buffer) throws IOException
+    protected long readLong(DataInput buffer) throws IOException
     {
         return buffer.readLong();
     }
 
-    protected void writeLong(DataOutputStream buffer, long l) throws IOException
+    protected void writeLong(DataOutput buffer, long l) throws IOException
     {
         buffer.writeLong(l);
     }
@@ -174,27 +176,27 @@
         return (response == null) ? 4 : response.length + 4;
     }
 
-    protected void writeBytes(DataOutputStream buffer, byte[] data) throws IOException
+    protected void writeBytes(DataOutput buffer, byte[] data) throws IOException
     {
         EncodingUtils.writeBytes(buffer,data);
     }
 
-    protected byte[] readBytes(DataInputStream buffer) throws IOException
+    protected byte[] readBytes(DataInput buffer) throws IOException
     {
         return EncodingUtils.readBytes(buffer);
     }
 
-    protected short readShort(DataInputStream buffer) throws IOException
+    protected short readShort(DataInput buffer) throws IOException
     {
         return EncodingUtils.readShort(buffer);
     }
 
-    protected void writeShort(DataOutputStream buffer, short s) throws IOException
+    protected void writeShort(DataOutput buffer, short s) throws IOException
     {
         EncodingUtils.writeShort(buffer, s);
     }
 
-    protected Content readContent(DataInputStream buffer)
+    protected Content readContent(DataInput buffer)
     {
         return null;
     }
@@ -204,56 +206,56 @@
         return 0;
     }
 
-    protected void writeContent(DataOutputStream buffer, Content body)
+    protected void writeContent(DataOutput buffer, Content body)
     {
     }
 
-    protected byte readBitfield(DataInputStream buffer) throws IOException
+    protected byte readBitfield(DataInput buffer) throws IOException
     {
         return readByte(buffer);
     }
 
-    protected int readUnsignedShort(DataInputStream buffer) throws IOException
+    protected int readUnsignedShort(DataInput buffer) throws IOException
     {
         return buffer.readUnsignedShort();
     }
 
-    protected void writeBitfield(DataOutputStream buffer, byte bitfield0) throws IOException
+    protected void writeBitfield(DataOutput buffer, byte bitfield0) throws IOException
     {
         buffer.writeByte(bitfield0);
     }
 
-    protected void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException
+    protected void writeUnsignedShort(DataOutput buffer, int s) throws IOException
     {
         EncodingUtils.writeUnsignedShort(buffer, s);
     }
 
-    protected long readUnsignedInteger(DataInputStream buffer) throws IOException
+    protected long readUnsignedInteger(DataInput buffer) throws IOException
     {
         return EncodingUtils.readUnsignedInteger(buffer);
     }
-    protected void writeUnsignedInteger(DataOutputStream buffer, long i) throws IOException
+    protected void writeUnsignedInteger(DataOutput buffer, long i) throws IOException
     {
         EncodingUtils.writeUnsignedInteger(buffer, i);
     }
 
 
-    protected short readUnsignedByte(DataInputStream buffer) throws IOException
+    protected short readUnsignedByte(DataInput buffer) throws IOException
     {
         return (short) buffer.readUnsignedByte();
     }
 
-    protected void writeUnsignedByte(DataOutputStream buffer, short unsignedByte) throws IOException
+    protected void writeUnsignedByte(DataOutput buffer, short unsignedByte) throws IOException
     {
         EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
     }
 
-    protected long readTimestamp(DataInputStream buffer) throws IOException
+    protected long readTimestamp(DataInput buffer) throws IOException
     {
         return EncodingUtils.readTimestamp(buffer);
     }
 
-    protected void writeTimestamp(DataOutputStream buffer, long t) throws IOException
+    protected void writeTimestamp(DataOutput buffer, long t) throws IOException
     {
         EncodingUtils.writeTimestamp(buffer, t);
     }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java
index df4d8bd..88b1ca7 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java
@@ -21,11 +21,12 @@
 
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
+import org.apache.qpid.codec.MarkableDataInput;
+
 import java.io.IOException;
 
 
 public abstract interface AMQMethodBodyInstanceFactory
 {
-    public AMQMethodBody newInstance(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException;
+    public AMQMethodBody newInstance(MarkableDataInput buffer, long size) throws AMQFrameDecodingException, IOException;
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
index cc9a33f..4ff7827 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
@@ -24,8 +24,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 import java.util.*;
 import java.lang.ref.WeakReference;
@@ -93,22 +94,44 @@
 
     private AMQShortString substring(final int from, final int to)
     {
-        return new AMQShortString(_data, from+_offset, to+_offset);
+        return new AMQShortString(_data, from+_offset, to-from);
     }
 
 
-    private static final ThreadLocal<Map<AMQShortString, WeakReference<AMQShortString>>> _localInternMap =
-            new ThreadLocal<Map<AMQShortString, WeakReference<AMQShortString>>>()
+    private static final int LOCAL_INTERN_CACHE_SIZE = 2048;
+
+    private static final ThreadLocal<Map<AMQShortString, AMQShortString>> _localInternMap =
+            new ThreadLocal<Map<AMQShortString, AMQShortString>>()
             {
-                protected Map<AMQShortString, WeakReference<AMQShortString>> initialValue()
+                protected Map<AMQShortString, AMQShortString> initialValue()
                 {
-                    return new WeakHashMap<AMQShortString, WeakReference<AMQShortString>>();
+                    return new LinkedHashMap<AMQShortString, AMQShortString>()
+                    {
+
+                        protected boolean removeEldestEntry(Map.Entry<AMQShortString, AMQShortString> eldest)
+                        {
+                            return size() > LOCAL_INTERN_CACHE_SIZE;
+                        }
+                    };
                 };
             };
 
     private static final Map<AMQShortString, WeakReference<AMQShortString>> _globalInternMap =
             new WeakHashMap<AMQShortString, WeakReference<AMQShortString>>();
 
+
+    private static final ThreadLocal<Map<String, WeakReference<AMQShortString>>> _localStringMap =
+            new ThreadLocal<Map<String, WeakReference<AMQShortString>>>()
+            {
+                protected Map<String, WeakReference<AMQShortString>> initialValue()
+                {
+                    return new WeakHashMap<String, WeakReference<AMQShortString>>();
+                };
+            };
+
+    private static final Map<String, WeakReference<AMQShortString>> _globalStringMap =
+            new WeakHashMap<String, WeakReference<AMQShortString>>();
+
     private static final Logger _logger = LoggerFactory.getLogger(AMQShortString.class);
 
     private final byte[] _data;
@@ -200,32 +223,32 @@
 
     }
 
-    private AMQShortString(DataInputStream data, final int length) throws IOException
+    private AMQShortString(DataInput data, final int length) throws IOException
     {
         if (length > MAX_LENGTH)
         {
             throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
         }
         byte[] dataBytes = new byte[length];
-        data.read(dataBytes);
+        data.readFully(dataBytes);
         _data = dataBytes;
         _offset = 0;
         _length = length;
 
     }
 
-    private AMQShortString(final byte[] data, final int from, final int to)
+    public AMQShortString(byte[] data, final int offset, final int length)
     {
-        if (data == null)
-        {
-            throw new NullPointerException("Cannot create AMQShortString with null data[]");
-        }
-        int length = to - from;
         if (length > MAX_LENGTH)
         {
             throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
         }
-        _offset = from;
+        if (data == null)
+        {
+            throw new NullPointerException("Cannot create AMQShortString with null data[]");
+        }
+
+        _offset = offset;
         _length = length;
         _data = data;
     }
@@ -234,9 +257,7 @@
     {
         if(_data.length != _length)
         {
-            byte[] dataBytes = new byte[_length];
-            System.arraycopy(_data,_offset,dataBytes,0,_length);
-            return new AMQShortString(dataBytes,0,_length);
+            return copy();
         }
         else
         {
@@ -265,7 +286,7 @@
         return new CharSubSequence(start, end);
     }
 
-    public static AMQShortString readFromBuffer(DataInputStream buffer) throws IOException
+    public static AMQShortString readFromBuffer(DataInput buffer) throws IOException
     {
         final int length = buffer.readUnsignedByte();
         if (length == 0)
@@ -293,12 +314,12 @@
         }
     }
 
-    public void writeToBuffer(DataOutputStream buffer) throws IOException
+    public void writeToBuffer(DataOutput buffer) throws IOException
     {
 
         final int size = length();
         //buffer.setAutoExpand(true);
-        buffer.write((byte) size);
+        buffer.writeByte(size);
         buffer.write(_data, _offset, size);
 
     }
@@ -420,7 +441,17 @@
     {
         if (_asString == null)
         {
-            _asString = new String(asChars());
+            AMQShortString intern = intern();
+
+            if(intern == this)
+            {
+                _asString = new String(asChars());
+            }
+            else
+            {
+                _asString = intern.asString();
+            }
+
         }
         return _asString;
     }
@@ -609,42 +640,51 @@
 
     public AMQShortString intern()
     {
+        return intern(true);
+    }
+
+    public AMQShortString intern(boolean keep)
+    {
 
         hashCode();
 
-        Map<AMQShortString, WeakReference<AMQShortString>> localMap =
+        Map<AMQShortString, AMQShortString> localMap =
                 _localInternMap.get();
 
-        WeakReference<AMQShortString> ref = localMap.get(this);
-        AMQShortString internString;
+        AMQShortString internString = localMap.get(this);
 
-        if(ref != null)
+
+        if(internString != null)
         {
-            internString = ref.get();
-            if(internString != null)
-            {
-                return internString;
-            }
+            return internString;
         }
 
 
+        WeakReference<AMQShortString> ref;
         synchronized(_globalInternMap)
         {
 
             ref = _globalInternMap.get(this);
             if((ref == null) || ((internString = ref.get()) == null))
             {
-                internString = shrink();
+                internString = keep ? shrink() : copy();
                 ref = new WeakReference(internString);
                 _globalInternMap.put(internString, ref);
             }
 
         }
-        localMap.put(internString, ref);
+        localMap.put(internString, internString);
         return internString;
 
     }
 
+    private AMQShortString copy()
+    {
+        byte[] dataBytes = new byte[_length];
+        System.arraycopy(_data,_offset,dataBytes,0,_length);
+        return new AMQShortString(dataBytes,0,_length);
+    }
+
     private int occurences(final byte delim)
     {
         int count = 0;
@@ -761,7 +801,46 @@
 
     public static AMQShortString valueOf(Object obj)
     {
-        return obj == null ? null : new AMQShortString(String.valueOf(obj));
+        return obj == null ? null : AMQShortString.valueOf(String.valueOf(obj));
+    }
+
+    public static AMQShortString valueOf(String obj)
+    {
+        if(obj == null)
+        {
+            return null;
+        }
+
+        Map<String, WeakReference<AMQShortString>> localMap =
+                _localStringMap.get();
+
+        WeakReference<AMQShortString> ref = localMap.get(obj);
+        AMQShortString internString;
+
+        if(ref != null)
+        {
+            internString = ref.get();
+            if(internString != null)
+            {
+                return internString;
+            }
+        }
+
+
+        synchronized(_globalStringMap)
+        {
+
+            ref = _globalStringMap.get(obj);
+            if((ref == null) || ((internString = ref.get()) == null))
+            {
+                internString = (new AMQShortString(obj)).intern();
+                ref = new WeakReference<AMQShortString>(internString);
+                _globalStringMap.put(obj, ref);
+            }
+
+        }
+        localMap.put(obj, ref);
+        return internString;
     }
 
 
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
index f3da64e..5c89af0 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
@@ -20,8 +20,8 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
 import java.io.IOException;
 import java.math.BigDecimal;
 
@@ -61,12 +61,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeLongStringBytes(buffer, (String) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readLongString(buffer);
         }
@@ -107,12 +107,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeUnsignedInteger(buffer, (Long) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readUnsignedInteger(buffer);
         }
@@ -138,7 +138,7 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             BigDecimal bd = (BigDecimal) value;
 
@@ -151,7 +151,7 @@
             EncodingUtils.writeInteger(buffer, unscaled);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             byte places = EncodingUtils.readByte(buffer);
 
@@ -183,12 +183,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeLong(buffer, (Long) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readLong(buffer);
         }
@@ -247,7 +247,7 @@
          * @param value  An instance of the type.
          * @param buffer The byte buffer to write it to.
          */
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             // Ensure that the value is a FieldTable.
             if (!(value instanceof FieldTable))
@@ -268,7 +268,7 @@
          *
          * @return An instance of the type.
          */
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             try
             {
@@ -302,10 +302,10 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer)
+        public void writeValueImpl(Object value, DataOutput buffer)
         { }
 
-        public Object readValueFromBuffer(DataInputStream buffer)
+        public Object readValueFromBuffer(DataInput buffer)
         {
             return null;
         }
@@ -331,12 +331,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeLongstr(buffer, (byte[]) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readLongstr(buffer);
         }
@@ -361,12 +361,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeLongStringBytes(buffer, (String) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readLongString(buffer);
         }
@@ -392,12 +392,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeLongStringBytes(buffer, (String) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readLongString(buffer);
         }
@@ -427,12 +427,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeBoolean(buffer, (Boolean) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readBoolean(buffer);
         }
@@ -462,12 +462,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeChar(buffer, (Character) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readChar(buffer);
         }
@@ -497,12 +497,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeByte(buffer, (Byte) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readByte(buffer);
         }
@@ -536,12 +536,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeShort(buffer, (Short) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readShort(buffer);
         }
@@ -578,12 +578,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeInteger(buffer, (Integer) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readInteger(buffer);
         }
@@ -596,6 +596,22 @@
             return EncodingUtils.encodedLongLength();
         }
 
+        public int getEncodingSize(long value)
+        {
+            return EncodingUtils.encodedLongLength();
+        }
+
+        public AMQTypedValue asTypedValue(long value)
+        {
+            return AMQTypedValue.createAMQTypedValue(value);
+        }
+
+        public void writeToBuffer(long value, DataOutput buffer) throws IOException
+        {
+            buffer.writeByte(identifier());
+            EncodingUtils.writeLong(buffer, value);
+        }
+
         public Object toNativeValue(Object value)
         {
             if (value instanceof Long)
@@ -625,12 +641,18 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeLong(buffer, (Long) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public long readLongFromBuffer(DataInput buffer) throws IOException
+        {
+            return EncodingUtils.readLong(buffer);
+        }
+
+
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readLong(buffer);
         }
@@ -660,12 +682,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeFloat(buffer, (Float) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readFloat(buffer);
         }
@@ -699,12 +721,12 @@
             }
         }
 
-        public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+        public void writeValueImpl(Object value, DataOutput buffer) throws IOException
         {
             EncodingUtils.writeDouble(buffer, (Double) value);
         }
 
-        public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+        public Object readValueFromBuffer(DataInput buffer) throws IOException
         {
             return EncodingUtils.readDouble(buffer);
         }
@@ -761,7 +783,7 @@
      */
     public AMQTypedValue asTypedValue(Object value)
     {
-        return new AMQTypedValue(this, toNativeValue(value));
+        return AMQTypedValue.createAMQTypedValue(this, toNativeValue(value));
     }
 
     /**
@@ -771,7 +793,7 @@
      * @param value  An instance of the type.
      * @param buffer The byte buffer to write it to.
      */
-    public void writeToBuffer(Object value, DataOutputStream buffer) throws IOException
+    public void writeToBuffer(Object value, DataOutput buffer) throws IOException
     {
         buffer.writeByte(identifier());
         writeValueImpl(value, buffer);
@@ -783,7 +805,7 @@
      * @param value  An instance of the type.
      * @param buffer The byte buffer to write it to.
      */
-    abstract void writeValueImpl(Object value, DataOutputStream buffer) throws IOException;
+    abstract void writeValueImpl(Object value, DataOutput buffer) throws IOException;
 
     /**
      * Reads an instance of the type from a specified byte buffer.
@@ -792,5 +814,5 @@
      *
      * @return An instance of the type.
      */
-    abstract Object readValueFromBuffer(DataInputStream buffer) throws IOException;
+    abstract Object readValueFromBuffer(DataInput buffer) throws IOException;
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
index 1dbedca..f64164c 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
@@ -20,9 +20,7 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import java.io.*;
 import java.util.Date;
 import java.util.Map;
 import java.math.BigDecimal;
@@ -42,83 +40,225 @@
  * <tr><td> Extract the value from a fully typed AMQP value.
  * </table>
  */
-public class AMQTypedValue
+public abstract class AMQTypedValue
 {
-    /** The type of the value. */
-    private final AMQType _type;
 
-    /** The Java native representation of the AMQP typed value. */
-    private final Object _value;
+    public abstract AMQType getType();
 
-    public AMQTypedValue(AMQType type, Object value)
+    public abstract Object getValue();
+
+    public abstract void writeToBuffer(DataOutput buffer) throws IOException;
+
+    public abstract int getEncodingSize();
+
+
+    private static final class GenericTypedValue extends AMQTypedValue
     {
-        if (type == null)
+        /** The type of the value. */
+        private final AMQType _type;
+
+        /** The Java native representation of the AMQP typed value. */
+        private final Object _value;
+
+        private GenericTypedValue(AMQType type, Object value)
         {
-            throw new NullPointerException("Cannot create a typed value with null type");
+            if (type == null)
+            {
+                throw new NullPointerException("Cannot create a typed value with null type");
+            }
+
+            _type = type;
+            _value = type.toNativeValue(value);
         }
 
-        _type = type;
-        _value = type.toNativeValue(value);
+        private GenericTypedValue(AMQType type, DataInput buffer) throws IOException
+        {
+            _type = type;
+            _value = type.readValueFromBuffer(buffer);
+        }
+
+
+        public AMQType getType()
+        {
+            return _type;
+        }
+
+        public Object getValue()
+        {
+            return _value;
+        }
+
+        public void writeToBuffer(DataOutput buffer) throws IOException
+        {
+            _type.writeToBuffer(_value, buffer);
+        }
+
+        public int getEncodingSize()
+        {
+            return _type.getEncodingSize(_value);
+        }
+
+
+        public String toString()
+        {
+            return "[" + getType() + ": " + getValue() + "]";
+        }
+
+
+        public boolean equals(Object o)
+        {
+            if(o instanceof GenericTypedValue)
+            {
+                GenericTypedValue other = (GenericTypedValue) o;
+                return _type == other._type && (_value == null ? other._value == null : _value.equals(other._value));
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public int hashCode()
+        {
+            return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode());
+        }
+
     }
 
-    private AMQTypedValue(AMQType type, DataInputStream buffer) throws IOException
+    private static final class LongTypedValue extends AMQTypedValue
     {
-        _type = type;
-        _value = type.readValueFromBuffer(buffer);
+
+        private final long _value;
+
+        private LongTypedValue(long value)
+        {
+            _value = value;
+        }
+
+        public LongTypedValue(DataInput buffer) throws IOException
+        {
+            _value = EncodingUtils.readLong(buffer);
+        }
+
+        public AMQType getType()
+        {
+            return AMQType.LONG;
+        }
+
+
+        public Object getValue()
+        {
+            return _value;
+        }
+
+        public void writeToBuffer(DataOutput buffer) throws IOException
+        {
+            EncodingUtils.writeByte(buffer,AMQType.LONG.identifier());
+            EncodingUtils.writeLong(buffer,_value);
+        }
+
+
+        public int getEncodingSize()
+        {
+            return EncodingUtils.encodedLongLength();
+        }
     }
 
-    public AMQType getType()
+    private static final class IntTypedValue extends AMQTypedValue
     {
-        return _type;
+        @Override
+        public String toString()
+        {
+            return "[INT: " + String.valueOf(_value) + "]";
+        }
+
+        private final int _value;
+
+        public IntTypedValue(int value)
+        {
+            _value = value;
+        }
+
+        public AMQType getType()
+        {
+            return AMQType.INT;
+        }
+
+
+        public Object getValue()
+        {
+            return _value;
+        }
+
+        public void writeToBuffer(DataOutput buffer) throws IOException
+        {
+            EncodingUtils.writeByte(buffer,AMQType.INT.identifier());
+            EncodingUtils.writeInteger(buffer, _value);
+        }
+
+
+        public int getEncodingSize()
+        {
+            return EncodingUtils.encodedIntegerLength();
+        }
     }
 
-    public Object getValue()
-    {
-        return _value;
-    }
 
-    public void writeToBuffer(DataOutputStream buffer) throws IOException
-    {
-        _type.writeToBuffer(_value, buffer);
-    }
-
-    public int getEncodingSize()
-    {
-        return _type.getEncodingSize(_value);
-    }
-
-    public static AMQTypedValue readFromBuffer(DataInputStream buffer) throws IOException
+    public static AMQTypedValue readFromBuffer(DataInput buffer) throws IOException
     {
         AMQType type = AMQTypeMap.getType(buffer.readByte());
 
-        return new AMQTypedValue(type, buffer);
-    }
-
-    public String toString()
-    {
-        return "[" + getType() + ": " + getValue() + "]";
-    }
-
-
-    public boolean equals(Object o)
-    {
-        if(o instanceof AMQTypedValue)
+        switch(type)
         {
-            AMQTypedValue other = (AMQTypedValue) o;
-            return _type == other._type && (_value == null ? other._value == null : _value.equals(other._value));
+            case LONG:
+                return new LongTypedValue(buffer);
+
+            case INT:
+                int value = EncodingUtils.readInteger(buffer);
+                return createAMQTypedValue(value);
+
+            default:
+                return new GenericTypedValue(type, buffer);
         }
-        else
+
+    }
+
+    private static final AMQTypedValue[] INT_VALUES = new AMQTypedValue[16];
+    static
+    {
+        for(int i = 0 ; i < 16; i ++)
         {
-            return false;
+            INT_VALUES[i] = new IntTypedValue(i);
         }
     }
 
-    public int hashCode()
+    public static AMQTypedValue createAMQTypedValue(int i)
     {
-        return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode());
+        return (i & 0x0f) == i ? INT_VALUES[i] : new IntTypedValue(i);
     }
 
 
+    public static AMQTypedValue createAMQTypedValue(long value)
+    {
+        return new LongTypedValue(value);
+    }
+
+    public static AMQTypedValue createAMQTypedValue(AMQType type, Object value)
+    {
+        switch(type)
+        {
+            case LONG:
+                return new LongTypedValue((Long) AMQType.LONG.toNativeValue(value));
+            case INT:
+                return new IntTypedValue((Integer) AMQType.INT.toNativeValue(value));
+
+            default:
+                return new GenericTypedValue(type, value);
+        }
+    }
+
+
+
     public static AMQTypedValue toTypedValue(Object val)
     {
         if(val == null)
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
index 57622b5..2739f7d 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
@@ -20,8 +20,9 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 
 import org.slf4j.Logger;
@@ -80,6 +81,7 @@
     private static final int USER_ID_MASK = 1 << 4;
     private static final int APPLICATION_ID_MASK = 1 << 3;
     private static final int CLUSTER_ID_MASK = 1 << 2;
+    private byte[] _encodedForm;
 
 
     public BasicContentHeaderProperties()
@@ -87,6 +89,12 @@
 
     public int getPropertyListSize()
     {
+        if(_encodedForm != null && (_headers == null || _headers.isClean()))
+        {
+            return _encodedForm.length;
+        }
+        else
+        {
             int size = 0;
 
             if ((_propertyFlags & (CONTENT_TYPE_MASK)) > 0)
@@ -167,6 +175,7 @@
             }
 
             return size;
+        }
     }
 
     public void setPropertyFlags(int propertyFlags)
@@ -179,87 +188,94 @@
         return _propertyFlags;
     }
 
-    public void writePropertyListPayload(DataOutputStream buffer) throws IOException
+    public void writePropertyListPayload(DataOutput buffer) throws IOException
     {
-        if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
+        if(_encodedForm != null && (_headers == null || !_headers.isClean()))
         {
-            EncodingUtils.writeShortStringBytes(buffer, _contentType);
+            buffer.write(_encodedForm);
         }
-
-        if ((_propertyFlags & ENCODING_MASK) != 0)
+        else
         {
-            EncodingUtils.writeShortStringBytes(buffer, _encoding);
-        }
-
-        if ((_propertyFlags & HEADERS_MASK) != 0)
-        {
-            EncodingUtils.writeFieldTableBytes(buffer, _headers);
-        }
-
-        if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
-        {
-            buffer.writeByte(_deliveryMode);
-        }
-
-        if ((_propertyFlags & PRIORITY_MASK) != 0)
-        {
-            buffer.writeByte(_priority);
-        }
-
-        if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _correlationId);
-        }
-
-        if ((_propertyFlags & REPLY_TO_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _replyTo);
-        }
-
-        if ((_propertyFlags & EXPIRATION_MASK) != 0)
-        {
-            if (_expiration == 0L)
+            if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
             {
-                EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING);
+                EncodingUtils.writeShortStringBytes(buffer, _contentType);
             }
-            else
+
+            if ((_propertyFlags & ENCODING_MASK) != 0)
             {
-                EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration));
+                EncodingUtils.writeShortStringBytes(buffer, _encoding);
             }
-        }
 
-        if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _messageId);
-        }
+            if ((_propertyFlags & HEADERS_MASK) != 0)
+            {
+                EncodingUtils.writeFieldTableBytes(buffer, _headers);
+            }
 
-        if ((_propertyFlags & TIMESTAMP_MASK) != 0)
-        {
-            EncodingUtils.writeTimestamp(buffer, _timestamp);
-        }
+            if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
+            {
+                buffer.writeByte(_deliveryMode);
+            }
 
-        if ((_propertyFlags & TYPE_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _type);
-        }
+            if ((_propertyFlags & PRIORITY_MASK) != 0)
+            {
+                buffer.writeByte(_priority);
+            }
 
-        if ((_propertyFlags & USER_ID_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _userId);
-        }
+            if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _correlationId);
+            }
 
-        if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _appId);
-        }
+            if ((_propertyFlags & REPLY_TO_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _replyTo);
+            }
 
-        if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
-        {
-            EncodingUtils.writeShortStringBytes(buffer, _clusterId);
+            if ((_propertyFlags & EXPIRATION_MASK) != 0)
+            {
+                if (_expiration == 0L)
+                {
+                    EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING);
+                }
+                else
+                {
+                    EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration));
+                }
+            }
+
+            if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _messageId);
+            }
+
+            if ((_propertyFlags & TIMESTAMP_MASK) != 0)
+            {
+                EncodingUtils.writeTimestamp(buffer, _timestamp);
+            }
+
+            if ((_propertyFlags & TYPE_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _type);
+            }
+
+            if ((_propertyFlags & USER_ID_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _userId);
+            }
+
+            if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _appId);
+            }
+
+            if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
+            {
+                EncodingUtils.writeShortStringBytes(buffer, _clusterId);
+            }
         }
     }
 
-    public void populatePropertiesFromBuffer(DataInputStream buffer, int propertyFlags, int size) throws AMQFrameDecodingException, IOException
+    public void populatePropertiesFromBuffer(DataInput buffer, int propertyFlags, int size) throws AMQFrameDecodingException, IOException
     {
         _propertyFlags = propertyFlags;
 
@@ -268,26 +284,40 @@
             _logger.debug("Property flags: " + _propertyFlags);
         }
 
-        decode(buffer);
+        _encodedForm = new byte[size];
+        buffer.readFully(_encodedForm);
+
+        ByteArrayDataInput input = new ByteArrayDataInput(_encodedForm);
+
+        decode(input);
+
     }
 
-    private void decode(DataInputStream buffer) throws IOException, AMQFrameDecodingException
+    private void decode(ByteArrayDataInput buffer) throws IOException, AMQFrameDecodingException
     {
         // ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
 
+            int headersOffset = 0;
+
             if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
             {
-                _contentType = EncodingUtils.readAMQShortString(buffer);
+                _contentType = buffer.readAMQShortString();
+                headersOffset += EncodingUtils.encodedShortStringLength(_contentType);
             }
 
             if ((_propertyFlags & ENCODING_MASK) != 0)
             {
-                _encoding = EncodingUtils.readAMQShortString(buffer);
+                _encoding = buffer.readAMQShortString();
+                headersOffset += EncodingUtils.encodedShortStringLength(_encoding);
             }
 
             if ((_propertyFlags & HEADERS_MASK) != 0)
             {
-                _headers = EncodingUtils.readFieldTable(buffer);
+                long length = EncodingUtils.readUnsignedInteger(buffer);
+
+                _headers = new FieldTable(_encodedForm, headersOffset+4, (int)length);
+
+                buffer.skipBytes((int)length);
             }
 
             if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
@@ -302,12 +332,12 @@
 
             if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
             {
-                _correlationId = EncodingUtils.readAMQShortString(buffer);
+                _correlationId = buffer.readAMQShortString();
             }
 
             if ((_propertyFlags & REPLY_TO_MASK) != 0)
             {
-                _replyTo = EncodingUtils.readAMQShortString(buffer);
+                _replyTo = buffer.readAMQShortString();
             }
 
             if ((_propertyFlags & EXPIRATION_MASK) != 0)
@@ -317,7 +347,7 @@
 
             if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
             {
-                _messageId = EncodingUtils.readAMQShortString(buffer);
+                _messageId = buffer.readAMQShortString();
             }
 
             if ((_propertyFlags & TIMESTAMP_MASK) != 0)
@@ -327,22 +357,22 @@
 
             if ((_propertyFlags & TYPE_MASK) != 0)
             {
-                _type = EncodingUtils.readAMQShortString(buffer);
+                _type = buffer.readAMQShortString();
             }
 
             if ((_propertyFlags & USER_ID_MASK) != 0)
             {
-                _userId = EncodingUtils.readAMQShortString(buffer);
+                _userId = buffer.readAMQShortString();
             }
 
             if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
             {
-                _appId = EncodingUtils.readAMQShortString(buffer);
+                _appId = buffer.readAMQShortString();
             }
 
             if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
             {
-                _clusterId = EncodingUtils.readAMQShortString(buffer);
+                _clusterId = buffer.readAMQShortString();
             }
 
 
@@ -363,11 +393,12 @@
     {
         _propertyFlags |= (CONTENT_TYPE_MASK);
         _contentType = contentType;
+        _encodedForm = null;
     }
 
     public void setContentType(String contentType)
     {
-        setContentType((contentType == null) ? null : new AMQShortString(contentType));
+        setContentType((contentType == null) ? null : AMQShortString.valueOf(contentType));
     }
 
     public String getEncodingAsString()
@@ -384,13 +415,15 @@
     public void setEncoding(String encoding)
     {
         _propertyFlags |= ENCODING_MASK;
-        _encoding = (encoding == null) ? null : new AMQShortString(encoding);
+        _encoding = (encoding == null) ? null : AMQShortString.valueOf(encoding);
+        _encodedForm = null;
     }
 
     public void setEncoding(AMQShortString encoding)
     {
         _propertyFlags |= ENCODING_MASK;
         _encoding = encoding;
+        _encodedForm = null;
     }
 
     public FieldTable getHeaders()
@@ -407,6 +440,7 @@
     {
         _propertyFlags |= HEADERS_MASK;
         _headers = headers;
+        _encodedForm = null;
     }
 
     public byte getDeliveryMode()
@@ -418,6 +452,7 @@
     {
         _propertyFlags |= DELIVERY_MODE_MASK;
         _deliveryMode = deliveryMode;
+        _encodedForm = null;
     }
 
     public byte getPriority()
@@ -429,6 +464,7 @@
     {
         _propertyFlags |= PRIORITY_MASK;
         _priority = priority;
+        _encodedForm = null;
     }
 
     public AMQShortString getCorrelationId()
@@ -443,13 +479,14 @@
 
     public void setCorrelationId(String correlationId)
     {
-        setCorrelationId((correlationId == null) ? null : new AMQShortString(correlationId));
+        setCorrelationId((correlationId == null) ? null : AMQShortString.valueOf(correlationId));
     }
 
     public void setCorrelationId(AMQShortString correlationId)
     {
         _propertyFlags |= CORRELATION_ID_MASK;
         _correlationId = correlationId;
+        _encodedForm = null;
     }
 
     public String getReplyToAsString()
@@ -464,13 +501,14 @@
 
     public void setReplyTo(String replyTo)
     {
-        setReplyTo((replyTo == null) ? null : new AMQShortString(replyTo));
+        setReplyTo((replyTo == null) ? null : AMQShortString.valueOf(replyTo));
     }
 
     public void setReplyTo(AMQShortString replyTo)
     {
         _propertyFlags |= REPLY_TO_MASK;
         _replyTo = replyTo;
+        _encodedForm = null;
     }
 
     public long getExpiration()
@@ -482,6 +520,7 @@
     {
         _propertyFlags |= EXPIRATION_MASK;
         _expiration = expiration;
+        _encodedForm = null;
     }
 
     public AMQShortString getMessageId()
@@ -498,12 +537,14 @@
     {
         _propertyFlags |= MESSAGE_ID_MASK;
         _messageId = (messageId == null) ? null : new AMQShortString(messageId);
+        _encodedForm = null;
     }
 
     public void setMessageId(AMQShortString messageId)
     {
         _propertyFlags |= MESSAGE_ID_MASK;
         _messageId = messageId;
+        _encodedForm = null;
     }
 
     public long getTimestamp()
@@ -515,6 +556,7 @@
     {
         _propertyFlags |= TIMESTAMP_MASK;
         _timestamp = timestamp;
+        _encodedForm = null;
     }
 
     public String getTypeAsString()
@@ -529,13 +571,14 @@
 
     public void setType(String type)
     {
-        setType((type == null) ? null : new AMQShortString(type));
+        setType((type == null) ? null : AMQShortString.valueOf(type));
     }
 
     public void setType(AMQShortString type)
     {
         _propertyFlags |= TYPE_MASK;
         _type = type;
+        _encodedForm = null;
     }
 
     public String getUserIdAsString()
@@ -550,13 +593,14 @@
 
     public void setUserId(String userId)
     {
-        setUserId((userId == null) ? null : new AMQShortString(userId));
+        setUserId((userId == null) ? null : AMQShortString.valueOf(userId));
     }
 
     public void setUserId(AMQShortString userId)
     {
         _propertyFlags |= USER_ID_MASK;
         _userId = userId;
+        _encodedForm = null;
     }
 
     public String getAppIdAsString()
@@ -571,13 +615,14 @@
 
     public void setAppId(String appId)
     {
-        setAppId((appId == null) ? null : new AMQShortString(appId));
+        setAppId((appId == null) ? null : AMQShortString.valueOf(appId));
     }
 
     public void setAppId(AMQShortString appId)
     {
         _propertyFlags |= APPLICATION_ID_MASK;
         _appId = appId;
+        _encodedForm = null;
     }
 
     public String getClusterIdAsString()
@@ -592,13 +637,14 @@
 
     public void setClusterId(String clusterId)
     {
-        setClusterId((clusterId == null) ? null : new AMQShortString(clusterId));
+        setClusterId((clusterId == null) ? null : AMQShortString.valueOf(clusterId));
     }
 
     public void setClusterId(AMQShortString clusterId)
     {
         _propertyFlags |= CLUSTER_ID_MASK;
         _clusterId = clusterId;
+        _encodedForm = null;
     }
 
     public String toString()
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java
index f9580d8..554e937 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java
@@ -20,7 +20,8 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
+import org.apache.qpid.codec.MarkableDataInput;
+
 import java.io.IOException;
 
 /**
@@ -28,5 +29,5 @@
  */
 public interface BodyFactory
 {
-    AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException;
+    AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException;
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ByteArrayDataInput.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ByteArrayDataInput.java
new file mode 100644
index 0000000..6561856
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ByteArrayDataInput.java
@@ -0,0 +1,174 @@
+package org.apache.qpid.framing;
+
+import org.apache.qpid.codec.MarkableDataInput;
+
+import java.io.IOException;
+
+public class ByteArrayDataInput implements ExtendedDataInput, MarkableDataInput
+{
+    private byte[] _data;
+    private int _offset;
+    private int _length;
+    private int _origin;
+    private int _mark;
+
+    public ByteArrayDataInput(byte[] data)
+    {
+        this(data,0, data.length);
+    }
+
+    public ByteArrayDataInput(byte[] data, int offset, int length)
+    {
+        _data = data;
+        _offset = offset;
+        _length = length;
+        _origin = offset;
+        _mark = 0;
+    }
+
+    public void readFully(byte[] b)
+    {
+        System.arraycopy(_data,_offset,b,0,b.length);
+        _offset+=b.length;
+    }
+
+    public void readFully(byte[] b, int off, int len)
+    {
+        System.arraycopy(_data,_offset,b,off,len);
+        _offset+=len;
+    }
+
+    public int skipBytes(int n)
+    {
+        return _offset+=n;
+    }
+
+    public boolean readBoolean()
+    {
+        return _data[_offset++] != 0;
+    }
+
+    public byte readByte()
+    {
+        return _data[_offset++];
+    }
+
+    public int readUnsignedByte()
+    {
+        return ((int)_data[_offset++]) & 0xFF;
+    }
+
+    public short readShort()
+    {
+        return (short) (((((int)_data[_offset++]) << 8) & 0xFF00) | (((int)_data[_offset++]) & 0xFF));
+    }
+
+    public int readUnsignedShort()
+    {
+        return (((((int)_data[_offset++]) << 8) & 0xFF00) | (((int)_data[_offset++]) & 0xFF));
+    }
+
+    public char readChar()
+    {
+        return (char) (((((int)_data[_offset++]) << 8) & 0xFF00) | (((int)_data[_offset++]) & 0xFF));
+    }
+
+    public int readInt()
+    {
+        return  ((((int)_data[_offset++]) << 24) & 0xFF000000)
+                | ((((int)_data[_offset++]) << 16) & 0xFF0000)
+                | ((((int)_data[_offset++]) << 8) & 0xFF00)
+                | (((int)_data[_offset++]) & 0xFF);
+    }
+
+    public long readLong()
+    {
+        return    ((((long)_data[_offset++]) << 56) & 0xFF00000000000000L)
+                | ((((long)_data[_offset++]) << 48) & 0xFF000000000000L)
+                | ((((long)_data[_offset++]) << 40) & 0xFF0000000000L)
+                | ((((long)_data[_offset++]) << 32) & 0xFF00000000L)
+                | ((((long)_data[_offset++]) << 24) & 0xFF000000L)
+                | ((((long)_data[_offset++]) << 16) & 0xFF0000L)
+                | ((((long)_data[_offset++]) << 8)  & 0xFF00L)
+                | (((long)_data[_offset++]) & 0xFFL);
+    }
+
+    public float readFloat()
+    {
+        return Float.intBitsToFloat(readInt());
+    }
+
+    public double readDouble()
+    {
+        return Double.longBitsToDouble(readLong());
+    }
+
+    public AMQShortString readAMQShortString()
+    {
+        int length = _data[_offset++] & 0xff;
+        if(length == 0) 
+        {
+            return null;
+        }
+        else
+        {
+            final AMQShortString amqShortString = new AMQShortString(_data, _offset, length);
+            _offset+=length;
+            return amqShortString;
+        }
+    }
+
+    public String readLine()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public String readUTF()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public int available()
+    {
+        return (_origin+_length)-_offset;
+    }
+
+
+    public long skip(long i)
+    {
+        _offset+=i;
+        return i;
+    }
+
+    public int read(byte[] b)
+    {
+        readFully(b);
+        return b.length;
+    }
+
+    public int position()
+    {
+        return _offset - _origin;
+    }
+
+    public void position(int position)
+    {
+        _offset = position + _origin;
+    }
+
+    public int length()
+    {
+        return _length;
+    }
+
+
+    public void mark(int readAhead)
+    {
+        _mark = _offset-_origin;
+    }
+
+    public void reset()
+    {
+        _offset = _origin + _mark;
+    }
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java
index 15bc20c..098e365 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java
@@ -20,7 +20,7 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 
 public class CompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQDataBlock
@@ -50,7 +50,7 @@
         return frameSize;
     }
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
         for (int i = 0; i < _blocks.length; i++)
         {
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java
index aedb35f..541d104 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java
@@ -20,9 +20,11 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
 import org.apache.qpid.AMQException;
@@ -37,10 +39,10 @@
     {
     }
 
-    public ContentBody(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException
+    public ContentBody(DataInput buffer, long size) throws AMQFrameDecodingException, IOException
     {
         _payload = new byte[(int)size];
-        buffer.read(_payload);
+        buffer.readFully(_payload);
     }
 
 
@@ -59,7 +61,7 @@
         return _payload == null ? 0 : _payload.length;
     }
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
         buffer.write(_payload);
     }
@@ -84,11 +86,62 @@
     {
     }
 
+    private static class BufferContentBody implements AMQBody
+    {
+        private final int _length;
+        private final int _offset;
+        private final ByteBuffer _buf;
 
+        private BufferContentBody( ByteBuffer buf, int offset, int length)
+        {
+            _length = length;
+            _offset = offset;
+            _buf = buf;
+        }
+
+        public byte getFrameType()
+        {
+            return TYPE;
+        }
+
+
+        public int getSize()
+        {
+            return _length;
+        }
+
+        public void writePayload(DataOutput buffer) throws IOException
+        {
+            if(_buf.hasArray())
+            {
+                buffer.write(_buf.array(), _buf.arrayOffset() +  _offset, _length);
+            }
+            else
+            {
+                byte[] data = new byte[_length];
+                ByteBuffer buf = _buf.duplicate();
+
+                buf.position(_offset);
+                buf.limit(_offset+_length);
+                buf.get(data);
+                buffer.write(data);
+            }
+        }
+
+
+        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException
+        {
+            throw new RuntimeException("Buffered Body only to be used for outgoing data");
+        }
+    }
+
+    public static AMQFrame createAMQFrame(int channelId, ByteBuffer buf, int offset, int length)
+    {
+        return new AMQFrame(channelId, new BufferContentBody(buf, offset, length));
+    }
 
     public static AMQFrame createAMQFrame(int channelId, ContentBody body)
     {
-        final AMQFrame frame = new AMQFrame(channelId, body);
-        return frame;
+        return new AMQFrame(channelId, body);
     }
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java
index a0b030a..de2ffe9 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java
@@ -20,9 +20,9 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
 import java.io.IOException;
 
+import org.apache.qpid.codec.MarkableDataInput;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,7 +42,7 @@
         _log.debug("Creating content body factory");
     }
 
-    public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException
+    public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException
     {
         return new ContentBody(in, bodySize);
     }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java
index 18d0f26..8a2ad53 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java
@@ -20,8 +20,9 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 
 import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
@@ -45,7 +46,7 @@
     {
     }
 
-    public ContentHeaderBody(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException
+    public ContentHeaderBody(DataInput buffer, long size) throws AMQFrameDecodingException, IOException
     {
         classId = buffer.readUnsignedShort();
         weight = buffer.readUnsignedShort();
@@ -106,7 +107,7 @@
         return 2 + 2 + 8 + 2 + properties.getPropertyListSize();
     }
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
         EncodingUtils.writeUnsignedShort(buffer, classId);
         EncodingUtils.writeUnsignedShort(buffer, weight);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java
index a474e33..c3e4c69 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java
@@ -20,9 +20,9 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
 import java.io.IOException;
 
+import org.apache.qpid.codec.MarkableDataInput;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,7 +42,7 @@
         _log.debug("Creating content header body factory");
     }
 
-    public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException
+    public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException, IOException
     {
         // all content headers are the same - it is only the properties that differ.
         // the content header body further delegates construction of properties
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java
index 237929f..ea8358a 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java
@@ -20,8 +20,9 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 
 
@@ -35,7 +36,7 @@
      * Writes the property list to the buffer, in a suitably encoded form.
      * @param buffer The buffer to write to
      */
-    void writePropertyListPayload(DataOutputStream buffer) throws IOException;
+    void writePropertyListPayload(DataOutput buffer) throws IOException;
 
     /**
      * Populates the properties from buffer.
@@ -43,7 +44,7 @@
      * @param propertyFlags he property flags.
      * @throws AMQFrameDecodingException when the buffer does not contain valid data
      */
-    void populatePropertiesFromBuffer(DataInputStream buffer, int propertyFlags, int size)
+    void populatePropertiesFromBuffer(DataInput buffer, int propertyFlags, int size)
         throws AMQFrameDecodingException, IOException;
 
     /**
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java
index 43ee8cd..48bd528 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.IOException;
 
@@ -39,7 +40,7 @@
     }
 
     public ContentHeaderProperties createContentHeaderProperties(int classId, int propertyFlags,
-                                                                 DataInputStream buffer, int size)
+                                                                 DataInput buffer, int size)
              throws AMQFrameDecodingException, IOException
     {
         ContentHeaderProperties properties;
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
index 2d7e274..e018407 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
@@ -219,7 +219,7 @@
         return 0;
     }
 
-    public static void writeShortStringBytes(DataOutputStream buffer, String s) throws IOException
+    public static void writeShortStringBytes(DataOutput buffer, String s) throws IOException
     {
         if (s != null)
         {
@@ -243,7 +243,7 @@
         }
     }
 
-    public static void writeShortStringBytes(DataOutputStream buffer, AMQShortString s) throws IOException
+    public static void writeShortStringBytes(DataOutput buffer, AMQShortString s) throws IOException
     {
         if (s != null)
         {
@@ -257,7 +257,7 @@
         }
     }
 
-    public static void writeLongStringBytes(DataOutputStream buffer, String s) throws IOException
+    public static void writeLongStringBytes(DataOutput buffer, String s) throws IOException
     {
         assert (s == null) || (s.length() <= 0xFFFE);
         if (s != null)
@@ -279,7 +279,7 @@
         }
     }
 
-    public static void writeLongStringBytes(DataOutputStream buffer, char[] s) throws IOException
+    public static void writeLongStringBytes(DataOutput buffer, char[] s) throws IOException
     {
         assert (s == null) || (s.length <= 0xFFFE);
         if (s != null)
@@ -300,7 +300,7 @@
         }
     }
 
-    public static void writeLongStringBytes(DataOutputStream buffer, byte[] bytes) throws IOException
+    public static void writeLongStringBytes(DataOutput buffer, byte[] bytes) throws IOException
     {
         assert (bytes == null) || (bytes.length <= 0xFFFE);
         if (bytes != null)
@@ -314,13 +314,13 @@
         }
     }
 
-    public static void writeUnsignedByte(DataOutputStream buffer, short b) throws IOException
+    public static void writeUnsignedByte(DataOutput buffer, short b) throws IOException
     {
         byte bv = (byte) b;
         buffer.write(bv);
     }
 
-    public static void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException
+    public static void writeUnsignedShort(DataOutput buffer, int s) throws IOException
     {
         // TODO: Is this comparison safe? Do I need to cast RHS to long?
         if (s < Short.MAX_VALUE)
@@ -340,7 +340,7 @@
         return 4;
     }
 
-    public static void writeUnsignedInteger(DataOutputStream buffer, long l) throws IOException
+    public static void writeUnsignedInteger(DataOutput buffer, long l) throws IOException
     {
         // TODO: Is this comparison safe? Do I need to cast RHS to long?
         if (l < Integer.MAX_VALUE)
@@ -360,7 +360,7 @@
         }
     }
 
-    public static void writeFieldTableBytes(DataOutputStream buffer, FieldTable table) throws IOException
+    public static void writeFieldTableBytes(DataOutput buffer, FieldTable table) throws IOException
     {
         if (table != null)
         {
@@ -372,12 +372,12 @@
         }
     }
 
-    public static void writeContentBytes(DataOutputStream buffer, Content content)
+    public static void writeContentBytes(DataOutput buffer, Content content)
     {
         // TODO: New Content class required for AMQP 0-9.
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean[] values) throws IOException
+    public static void writeBooleans(DataOutput buffer, boolean[] values) throws IOException
     {
         byte packedValue = 0;
         for (int i = 0; i < values.length; i++)
@@ -391,13 +391,13 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value) throws IOException
+    public static void writeBooleans(DataOutput buffer, boolean value) throws IOException
     {
 
         buffer.write(value ? (byte) 1 : (byte) 0);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1) throws IOException
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
 
@@ -409,7 +409,7 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2) throws IOException
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
 
@@ -426,7 +426,7 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3) throws IOException
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
 
@@ -448,7 +448,7 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3,
         boolean value4) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -476,7 +476,7 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3,
         boolean value4, boolean value5) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -509,7 +509,7 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3,
         boolean value4, boolean value5, boolean value6) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -547,7 +547,7 @@
         buffer.write(packedValue);
     }
 
-    public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+    public static void writeBooleans(DataOutput buffer, boolean value0, boolean value1, boolean value2, boolean value3,
         boolean value4, boolean value5, boolean value6, boolean value7) throws IOException
     {
         byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -596,7 +596,7 @@
      * @param buffer
      * @param data
      */
-    public static void writeLongstr(DataOutputStream buffer, byte[] data) throws IOException
+    public static void writeLongstr(DataOutput buffer, byte[] data) throws IOException
     {
         if (data != null)
         {
@@ -609,12 +609,12 @@
         }
     }
 
-    public static void writeTimestamp(DataOutputStream buffer, long timestamp) throws IOException
+    public static void writeTimestamp(DataOutput buffer, long timestamp) throws IOException
     {
         writeLong(buffer, timestamp);
     }
 
-    public static boolean[] readBooleans(DataInputStream buffer) throws IOException
+    public static boolean[] readBooleans(DataInput buffer) throws IOException
     {
         final byte packedValue = buffer.readByte();
         if (packedValue == 0)
@@ -641,7 +641,7 @@
         return result;
     }
 
-    public static FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException
+    public static FieldTable readFieldTable(DataInput buffer) throws AMQFrameDecodingException, IOException
     {
         long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
         if (length == 0)
@@ -654,19 +654,19 @@
         }
     }
 
-    public static Content readContent(DataInputStream buffer) throws AMQFrameDecodingException
+    public static Content readContent(DataInput buffer) throws AMQFrameDecodingException
     {
         // TODO: New Content class required for AMQP 0-9.
         return null;
     }
 
-    public static AMQShortString readAMQShortString(DataInputStream buffer) throws IOException
+    public static AMQShortString readAMQShortString(DataInput buffer) throws IOException
     {
         return AMQShortString.readFromBuffer(buffer);
 
     }
 
-    public static String readShortString(DataInputStream buffer) throws IOException
+    public static String readShortString(DataInput buffer) throws IOException
     {
         short length = (short) (((short)buffer.readByte()) & 0xFF);
         if (length == 0)
@@ -681,7 +681,7 @@
             // this approach here is valid since we know that all the chars are
             // ASCII (0-127)
             byte[] stringBytes = new byte[length];
-            buffer.read(stringBytes, 0, length);
+            buffer.readFully(stringBytes, 0, length);
             char[] stringChars = new char[length];
             for (int i = 0; i < stringChars.length; i++)
             {
@@ -692,7 +692,7 @@
         }
     }
 
-    public static String readLongString(DataInputStream buffer) throws IOException
+    public static String readLongString(DataInput buffer) throws IOException
     {
         long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
         if (length == 0)
@@ -707,7 +707,7 @@
             // this approach here is valid since we know that all the chars are
             // ASCII (0-127)
             byte[] stringBytes = new byte[(int) length];
-            buffer.read(stringBytes, 0, (int) length);
+            buffer.readFully(stringBytes, 0, (int) length);
             char[] stringChars = new char[(int) length];
             for (int i = 0; i < stringChars.length; i++)
             {
@@ -718,7 +718,7 @@
         }
     }
 
-    public static byte[] readLongstr(DataInputStream buffer) throws IOException
+    public static byte[] readLongstr(DataInput buffer) throws IOException
     {
         long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
         if (length == 0)
@@ -728,13 +728,13 @@
         else
         {
             byte[] result = new byte[(int) length];
-            buffer.read(result);
+            buffer.readFully(result);
 
             return result;
         }
     }
 
-    public static long readTimestamp(DataInputStream buffer) throws IOException
+    public static long readTimestamp(DataInput buffer) throws IOException
     {
         // Discard msb from AMQ timestamp
         // buffer.getUnsignedInt();
@@ -818,12 +818,12 @@
 
     // AMQP_BOOLEAN_PROPERTY_PREFIX
 
-    public static void writeBoolean(DataOutputStream buffer, Boolean aBoolean) throws IOException
+    public static void writeBoolean(DataOutput buffer, boolean aBoolean) throws IOException
     {
         buffer.write(aBoolean ? 1 : 0);
     }
 
-    public static boolean readBoolean(DataInputStream buffer) throws IOException
+    public static boolean readBoolean(DataInput buffer) throws IOException
     {
         byte packedValue = buffer.readByte();
 
@@ -836,12 +836,12 @@
     }
 
     // AMQP_BYTE_PROPERTY_PREFIX
-    public static void writeByte(DataOutputStream buffer, Byte aByte) throws IOException
+    public static void writeByte(DataOutput buffer, byte aByte) throws IOException
     {
         buffer.writeByte(aByte);
     }
 
-    public static byte readByte(DataInputStream buffer) throws IOException
+    public static byte readByte(DataInput buffer) throws IOException
     {
         return buffer.readByte();
     }
@@ -852,12 +852,12 @@
     }
 
     // AMQP_SHORT_PROPERTY_PREFIX
-    public static void writeShort(DataOutputStream buffer, Short aShort) throws IOException
+    public static void writeShort(DataOutput buffer, short aShort) throws IOException
     {
         buffer.writeShort(aShort);
     }
 
-    public static short readShort(DataInputStream buffer) throws IOException
+    public static short readShort(DataInput buffer) throws IOException
     {
         return buffer.readShort();
     }
@@ -868,12 +868,12 @@
     }
 
     // INTEGER_PROPERTY_PREFIX
-    public static void writeInteger(DataOutputStream buffer, Integer aInteger) throws IOException
+    public static void writeInteger(DataOutput buffer, int aInteger) throws IOException
     {
         buffer.writeInt(aInteger);
     }
 
-    public static int readInteger(DataInputStream buffer) throws IOException
+    public static int readInteger(DataInput buffer) throws IOException
     {
         return buffer.readInt();
     }
@@ -884,12 +884,12 @@
     }
 
     // AMQP_LONG_PROPERTY_PREFIX
-    public static void writeLong(DataOutputStream buffer, Long aLong) throws IOException
+    public static void writeLong(DataOutput buffer, long aLong) throws IOException
     {
         buffer.writeLong(aLong);
     }
 
-    public static long readLong(DataInputStream buffer) throws IOException
+    public static long readLong(DataInput buffer) throws IOException
     {
         return buffer.readLong();
     }
@@ -900,12 +900,12 @@
     }
 
     // Float_PROPERTY_PREFIX
-    public static void writeFloat(DataOutputStream buffer, Float aFloat) throws IOException
+    public static void writeFloat(DataOutput buffer, float aFloat) throws IOException
     {
         buffer.writeFloat(aFloat);
     }
 
-    public static float readFloat(DataInputStream buffer) throws IOException
+    public static float readFloat(DataInput buffer) throws IOException
     {
         return buffer.readFloat();
     }
@@ -916,12 +916,12 @@
     }
 
     // Double_PROPERTY_PREFIX
-    public static void writeDouble(DataOutputStream buffer, Double aDouble) throws IOException
+    public static void writeDouble(DataOutput buffer, Double aDouble) throws IOException
     {
         buffer.writeDouble(aDouble);
     }
 
-    public static double readDouble(DataInputStream buffer) throws IOException
+    public static double readDouble(DataInput buffer) throws IOException
     {
         return buffer.readDouble();
     }
@@ -931,7 +931,7 @@
         return 8;
     }
 
-    public static byte[] readBytes(DataInputStream buffer) throws IOException
+    public static byte[] readBytes(DataInput buffer) throws IOException
     {
         long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
         if (length == 0)
@@ -941,13 +941,13 @@
         else
         {
             byte[] dataBytes = new byte[(int)length];
-            buffer.read(dataBytes, 0, (int) length);
+            buffer.readFully(dataBytes, 0, (int) length);
 
             return dataBytes;
         }
     }
 
-    public static void writeBytes(DataOutputStream buffer, byte[] data) throws IOException
+    public static void writeBytes(DataOutput buffer, byte[] data) throws IOException
     {
         if (data != null)
         {
@@ -969,19 +969,19 @@
         return encodedByteLength();
     }
 
-    public static char readChar(DataInputStream buffer) throws IOException
+    public static char readChar(DataInput buffer) throws IOException
     {
         // This is valid as we know that the Character is ASCII 0..127
-        return (char) buffer.read();
+        return (char) buffer.readByte();
     }
 
-    public static void writeChar(DataOutputStream buffer, char character) throws IOException
+    public static void writeChar(DataOutput buffer, char character) throws IOException
     {
         // This is valid as we know that the Character is ASCII 0..127
         writeByte(buffer, (byte) character);
     }
 
-    public static long readLongAsShortString(DataInputStream buffer) throws IOException
+    public static long readLongAsShortString(DataInput buffer) throws IOException
     {
         short length = (short) buffer.readUnsignedByte();
         short pos = 0;
@@ -1018,7 +1018,7 @@
         return result;
     }
 
-    public static long readUnsignedInteger(DataInputStream buffer) throws IOException
+    public static long readUnsignedInteger(DataInput buffer) throws IOException
     {
         long l = 0xFF & buffer.readByte();
         l <<= 8;
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ExtendedDataInput.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ExtendedDataInput.java
new file mode 100644
index 0000000..c789d92
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ExtendedDataInput.java
@@ -0,0 +1,14 @@
+package org.apache.qpid.framing;
+
+import java.io.DataInput;
+
+public interface ExtendedDataInput extends DataInput
+{
+    AMQShortString readAMQShortString();
+
+    int available();
+
+    int position();
+
+    void position(int position);
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index 4a126b8..863e363 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -25,11 +25,7 @@
 
 import org.apache.qpid.AMQPInvalidClassException;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import java.io.*;
 import java.math.BigDecimal;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -44,18 +40,27 @@
 public class FieldTable
 {
     private static final Logger _logger = LoggerFactory.getLogger(FieldTable.class);
-    private static final String STRICT_AMQP = "STRICT_AMQP";
-    private final boolean _strictAMQP = Boolean.valueOf(System.getProperty(STRICT_AMQP, "false"));
+    private static final String STRICT_AMQP_NAME = "STRICT_AMQP";
+    private static final boolean STRICT_AMQP = Boolean.valueOf(System.getProperty(STRICT_AMQP_NAME, "false"));
 
     private byte[] _encodedForm;
+    private int _encodedFormOffset;
     private LinkedHashMap<AMQShortString, AMQTypedValue> _properties = null;
     private long _encodedSize;
     private static final int INITIAL_HASHMAP_CAPACITY = 16;
     private static final int INITIAL_ENCODED_FORM_SIZE = 256;
+    private final boolean _strictAMQP;
 
     public FieldTable()
     {
+        this(STRICT_AMQP);
+    }
+
+
+    public FieldTable(boolean strictAMQP)
+    {
         super();
+        _strictAMQP = strictAMQP;
     }
 
     /**
@@ -64,14 +69,28 @@
      * @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.
      */
-    public FieldTable(DataInputStream buffer, long length) throws IOException
+    public FieldTable(DataInput buffer, long length) throws IOException
     {
         this();
         _encodedForm = new byte[(int) length];
-        buffer.read(_encodedForm);
+        buffer.readFully(_encodedForm);
         _encodedSize = length;
     }
 
+    public FieldTable(byte[] encodedForm, int offset, int length) throws IOException
+    {
+        this();
+        _encodedForm = encodedForm;
+        _encodedFormOffset = offset;
+        _encodedSize = length;
+    }
+
+
+    public boolean isClean()
+    {
+        return _encodedForm != null;
+    }
+
     public AMQTypedValue getProperty(AMQShortString string)
     {
         checkPropertyName(string);
@@ -181,7 +200,7 @@
 
     public Boolean getBoolean(String string)
     {
-        return getBoolean(new AMQShortString(string));
+        return getBoolean(AMQShortString.valueOf(string));
     }
 
     public Boolean getBoolean(AMQShortString string)
@@ -199,7 +218,7 @@
 
     public Byte getByte(String string)
     {
-        return getByte(new AMQShortString(string));
+        return getByte(AMQShortString.valueOf(string));
     }
 
     public Byte getByte(AMQShortString string)
@@ -217,7 +236,7 @@
 
     public Short getShort(String string)
     {
-        return getShort(new AMQShortString(string));
+        return getShort(AMQShortString.valueOf(string));
     }
 
     public Short getShort(AMQShortString string)
@@ -235,7 +254,7 @@
 
     public Integer getInteger(String string)
     {
-        return getInteger(new AMQShortString(string));
+        return getInteger(AMQShortString.valueOf(string));
     }
 
     public Integer getInteger(AMQShortString string)
@@ -253,7 +272,7 @@
 
     public Long getLong(String string)
     {
-        return getLong(new AMQShortString(string));
+        return getLong(AMQShortString.valueOf(string));
     }
 
     public Long getLong(AMQShortString string)
@@ -271,7 +290,7 @@
 
     public Float getFloat(String string)
     {
-        return getFloat(new AMQShortString(string));
+        return getFloat(AMQShortString.valueOf(string));
     }
 
     public Float getFloat(AMQShortString string)
@@ -289,7 +308,7 @@
 
     public Double getDouble(String string)
     {
-        return getDouble(new AMQShortString(string));
+        return getDouble(AMQShortString.valueOf(string));
     }
 
     public Double getDouble(AMQShortString string)
@@ -307,7 +326,7 @@
 
     public String getString(String string)
     {
-        return getString(new AMQShortString(string));
+        return getString(AMQShortString.valueOf(string));
     }
 
     public String getString(AMQShortString string)
@@ -330,7 +349,7 @@
 
     public Character getCharacter(String string)
     {
-        return getCharacter(new AMQShortString(string));
+        return getCharacter(AMQShortString.valueOf(string));
     }
 
     public Character getCharacter(AMQShortString string)
@@ -348,7 +367,7 @@
 
     public byte[] getBytes(String string)
     {
-        return getBytes(new AMQShortString(string));
+        return getBytes(AMQShortString.valueOf(string));
     }
 
     public byte[] getBytes(AMQShortString string)
@@ -374,7 +393,7 @@
      */
     public FieldTable getFieldTable(String string)
     {
-        return getFieldTable(new AMQShortString(string));
+        return getFieldTable(AMQShortString.valueOf(string));
     }
 
     /**
@@ -401,7 +420,7 @@
 
     public Object getObject(String string)
     {
-        return getObject(new AMQShortString(string));
+        return getObject(AMQShortString.valueOf(string));
     }
 
     public Object getObject(AMQShortString string)
@@ -447,7 +466,7 @@
     // ************  Setters
     public Object setBoolean(String string, Boolean b)
     {
-        return setBoolean(new AMQShortString(string), b);
+        return setBoolean(AMQShortString.valueOf(string), b);
     }
 
     public Object setBoolean(AMQShortString string, Boolean b)
@@ -457,7 +476,7 @@
 
     public Object setByte(String string, Byte b)
     {
-        return setByte(new AMQShortString(string), b);
+        return setByte(AMQShortString.valueOf(string), b);
     }
 
     public Object setByte(AMQShortString string, Byte b)
@@ -467,7 +486,7 @@
 
     public Object setShort(String string, Short i)
     {
-        return setShort(new AMQShortString(string), i);
+        return setShort(AMQShortString.valueOf(string), i);
     }
 
     public Object setShort(AMQShortString string, Short i)
@@ -475,29 +494,29 @@
         return setProperty(string, AMQType.SHORT.asTypedValue(i));
     }
 
-    public Object setInteger(String string, Integer i)
+    public Object setInteger(String string, int i)
     {
-        return setInteger(new AMQShortString(string), i);
+        return setInteger(AMQShortString.valueOf(string), i);
     }
 
-    public Object setInteger(AMQShortString string, Integer i)
+    public Object setInteger(AMQShortString string, int i)
     {
-        return setProperty(string, AMQType.INT.asTypedValue(i));
+        return setProperty(string, AMQTypedValue.createAMQTypedValue(i));
     }
 
-    public Object setLong(String string, Long l)
+    public Object setLong(String string, long l)
     {
-        return setLong(new AMQShortString(string), l);
+        return setLong(AMQShortString.valueOf(string), l);
     }
 
-    public Object setLong(AMQShortString string, Long l)
+    public Object setLong(AMQShortString string, long l)
     {
-        return setProperty(string, AMQType.LONG.asTypedValue(l));
+        return setProperty(string, AMQTypedValue.createAMQTypedValue(l));
     }
 
     public Object setFloat(String string, Float f)
     {
-        return setFloat(new AMQShortString(string), f);
+        return setFloat(AMQShortString.valueOf(string), f);
     }
 
     public Object setFloat(AMQShortString string, Float v)
@@ -507,7 +526,7 @@
 
     public Object setDouble(String string, Double d)
     {
-        return setDouble(new AMQShortString(string), d);
+        return setDouble(AMQShortString.valueOf(string), d);
     }
 
     public Object setDouble(AMQShortString string, Double v)
@@ -517,7 +536,7 @@
 
     public Object setString(String string, String s)
     {
-        return setString(new AMQShortString(string), s);
+        return setString(AMQShortString.valueOf(string), s);
     }
 
     public Object setAsciiString(AMQShortString string, String value)
@@ -546,7 +565,7 @@
 
     public Object setChar(String string, char c)
     {
-        return setChar(new AMQShortString(string), c);
+        return setChar(AMQShortString.valueOf(string), c);
     }
 
     public Object setChar(AMQShortString string, char c)
@@ -556,7 +575,7 @@
 
     public Object setBytes(String string, byte[] b)
     {
-        return setBytes(new AMQShortString(string), b);
+        return setBytes(AMQShortString.valueOf(string), b);
     }
 
     public Object setBytes(AMQShortString string, byte[] bytes)
@@ -566,7 +585,7 @@
 
     public Object setBytes(String string, byte[] bytes, int start, int length)
     {
-        return setBytes(new AMQShortString(string), bytes, start, length);
+        return setBytes(AMQShortString.valueOf(string), bytes, start, length);
     }
 
     public Object setBytes(AMQShortString string, byte[] bytes, int start, int length)
@@ -579,7 +598,7 @@
 
     public Object setObject(String string, Object o)
     {
-        return setObject(new AMQShortString(string), o);
+        return setObject(AMQShortString.valueOf(string), o);
     }
 
     public Object setTimestamp(AMQShortString string, long datetime)
@@ -617,7 +636,7 @@
      */
     public Object setFieldTable(String string, FieldTable ftValue)
     {
-        return setFieldTable(new AMQShortString(string), ftValue);
+        return setFieldTable(AMQShortString.valueOf(string), ftValue);
     }
 
     /**
@@ -681,7 +700,7 @@
 
     public boolean isNullStringValue(String name)
     {
-        AMQTypedValue value = getProperty(new AMQShortString(name));
+        AMQTypedValue value = getProperty(AMQShortString.valueOf(name));
 
         return (value != null) && (value.getType() == AMQType.VOID);
     }
@@ -713,7 +732,7 @@
 
     public boolean itemExists(String string)
     {
-        return itemExists(new AMQShortString(string));
+        return itemExists(AMQShortString.valueOf(string));
     }
 
     public String toString()
@@ -769,7 +788,7 @@
 
     // *************************  Byte Buffer Processing
 
-    public void writeToBuffer(DataOutputStream buffer) throws IOException
+    public void writeToBuffer(DataOutput buffer) throws IOException
     {
         final boolean trace = _logger.isDebugEnabled();
 
@@ -919,7 +938,7 @@
 
     public boolean containsKey(String key)
     {
-        return containsKey(new AMQShortString(key));
+        return containsKey(AMQShortString.valueOf(key));
     }
 
     public Set<String> keys()
@@ -942,7 +961,7 @@
 
     public Object get(String key)
     {
-        return get(new AMQShortString(key));
+        return get(AMQShortString.valueOf(key));
     }
 
     public Object get(AMQShortString key)
@@ -958,7 +977,7 @@
     public Object remove(String key)
     {
 
-        return remove(new AMQShortString(key));
+        return remove(AMQShortString.valueOf(key));
 
     }
 
@@ -1005,12 +1024,12 @@
         return _properties.keySet();
     }
 
-    private void putDataInBuffer(DataOutputStream buffer) throws IOException
+    private void putDataInBuffer(DataOutput buffer) throws IOException
     {
 
         if (_encodedForm != null)
         {
-            buffer.write(_encodedForm);
+            buffer.write(_encodedForm,_encodedFormOffset,(int)_encodedSize);
         }
         else if (_properties != null)
         {
@@ -1039,9 +1058,8 @@
     private void setFromBuffer() throws AMQFrameDecodingException, IOException
     {
 
-        final ByteArrayInputStream in = new ByteArrayInputStream(_encodedForm);
-        DataInputStream buffer = new DataInputStream(in);
-        final boolean trace = _logger.isDebugEnabled();
+        ByteArrayDataInput baid = new ByteArrayDataInput(_encodedForm, _encodedFormOffset, (int)_encodedSize);
+
         if (_encodedSize > 0)
         {
 
@@ -1051,12 +1069,12 @@
             do
             {
 
-                final AMQShortString key = EncodingUtils.readAMQShortString(buffer);
-                AMQTypedValue value = AMQTypedValue.readFromBuffer(buffer);
+                final AMQShortString key = baid.readAMQShortString();
+                AMQTypedValue value = AMQTypedValue.readFromBuffer(baid);
                 _properties.put(key, value);
 
             }
-            while (in.available() > 0);
+            while (baid.available() > 0);
 
         }
 
@@ -1101,7 +1119,7 @@
             FieldTable table = new FieldTable();
             for(Map.Entry<String,Object> entry : map.entrySet())
             {
-                table.put(new AMQShortString(entry.getKey()), entry.getValue());
+                table.put(AMQShortString.valueOf(entry.getKey()), entry.getValue());
             }
 
             return table;
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
index 438a46f..af0c5b8 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.framing;
 
+import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.IOException;
 
@@ -30,7 +31,7 @@
         return new FieldTable();
     }
 
-    public static FieldTable newFieldTable(DataInputStream byteBuffer, long length) throws AMQFrameDecodingException, IOException
+    public static FieldTable newFieldTable(DataInput byteBuffer, long length) throws AMQFrameDecodingException, IOException
     {
         return new FieldTable(byteBuffer, length);
     }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
index a6ce721..95b6246 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
@@ -21,7 +21,7 @@
 package org.apache.qpid.framing;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 
 import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
@@ -56,7 +56,7 @@
         return 0;//heartbeats we generate have no payload
     }
 
-    public void writePayload(DataOutputStream buffer)
+    public void writePayload(DataOutput buffer)
     {
     }
 
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java
index dfc49c6..971caca 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java
@@ -20,12 +20,13 @@
  */
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
+import org.apache.qpid.codec.MarkableDataInput;
 
 public class HeartbeatBodyFactory implements BodyFactory
 {
-    public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException
+    public AMQBody createBody(MarkableDataInput in, long bodySize) throws AMQFrameDecodingException
     {
         return new HeartbeatBody();
     }
+
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
index 8c01831..2925724 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
@@ -21,13 +21,10 @@
 package org.apache.qpid.framing;
 
 import org.apache.qpid.AMQException;
+import org.apache.qpid.codec.MarkableDataInput;
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import java.io.*;
 
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteBuffer;
 import java.util.Arrays;
 
 public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQDataBlock
@@ -66,7 +63,7 @@
              pv.equals(ProtocolVersion.v0_91) ? 1 : pv.getMinorVersion());
     }
 
-    public ProtocolInitiation(DataInputStream in) throws IOException
+    public ProtocolInitiation(MarkableDataInput in) throws IOException
     {
         _protocolHeader = new byte[4];
         in.read(_protocolHeader);
@@ -82,7 +79,7 @@
         return 4 + 1 + 1 + 1 + 1;
     }
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
 
         buffer.write(_protocolHeader);
@@ -143,7 +140,7 @@
          * @return true if we have enough data to decode the PI frame fully, false if more
          * data is required
          */
-        public boolean decodable(DataInputStream in) throws IOException
+        public boolean decodable(MarkableDataInput in) throws IOException
         {
             return (in.available() >= 8);
         }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java
index d2925d1..dd854dd 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java
@@ -21,7 +21,7 @@
 
 package org.apache.qpid.framing;
 
-import java.io.DataOutputStream;
+import java.io.DataOutput;
 import java.io.IOException;
 
 public class SmallCompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQDataBlock
@@ -69,7 +69,7 @@
         return frameSize;
     }
 
-    public void writePayload(DataOutputStream buffer) throws IOException
+    public void writePayload(DataOutput buffer) throws IOException
     {
         if (_firstFrame != null)
         {
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java b/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java
index ed9136f..e770fdd 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java
@@ -23,6 +23,7 @@
 import java.io.DataInputStream;
 import java.io.IOException;
 
+import org.apache.qpid.codec.MarkableDataInput;
 import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
 
 import org.slf4j.Logger;
@@ -145,7 +146,7 @@
 
     }
 
-    public AMQMethodBody get(short classID, short methodID, DataInputStream in, long size) throws AMQFrameDecodingException, IOException
+    public AMQMethodBody get(short classID, short methodID, MarkableDataInput in, long size) throws AMQFrameDecodingException, IOException
     {
         AMQMethodBodyInstanceFactory bodyFactory;
         try
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java
deleted file mode 100644
index 8de0f93..0000000
--- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteJobQueue.java
+++ /dev/null
@@ -1,432 +0,0 @@
-package org.apache.qpid.pool;
-
-import java.util.AbstractQueue;
-import java.util.Iterator;
-import java.util.Collection;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/*
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
-public class ReadWriteJobQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable>
-{
-
-    private final AtomicInteger _count = new AtomicInteger(0);
-
-    private final ReentrantLock _takeLock = new ReentrantLock();
-
-    private final Condition _notEmpty = _takeLock.newCondition();
-
-    private final ReentrantLock _putLock = new ReentrantLock();
-
-    private final ConcurrentLinkedQueue<ReadWriteRunnable> _readJobQueue = new ConcurrentLinkedQueue<ReadWriteRunnable>();
-
-    private final ConcurrentLinkedQueue<ReadWriteRunnable> _writeJobQueue = new ConcurrentLinkedQueue<ReadWriteRunnable>();
-
-
-    private class ReadWriteJobIterator implements Iterator<Runnable>
-    {
-
-        private boolean _onReads;
-        private Iterator<ReadWriteRunnable> _iter = _writeJobQueue.iterator();
-
-        public boolean hasNext()
-        {
-            if(!_iter.hasNext())
-            {
-                if(_onReads)
-                {
-                    _iter = _readJobQueue.iterator();
-                    _onReads = true;
-                    return _iter.hasNext();
-                }
-                else
-                {
-                    return false;
-                }
-            }
-            else
-            {
-                return true;
-            }
-        }
-
-        public Runnable next()
-        {
-            if(_iter.hasNext())
-            {
-                return _iter.next();
-            }
-            else
-            {
-                return null;
-            }
-        }
-
-        public void remove()
-        {
-            _takeLock.lock();
-            try
-            {
-                _iter.remove();
-                _count.decrementAndGet();
-            }
-            finally
-            {
-                _takeLock.unlock();
-            }
-        }
-    }
-
-    public Iterator<Runnable> iterator()
-    {
-        return new ReadWriteJobIterator();
-    }
-
-    public int size()
-    {
-        return _count.get();
-    }
-
-    public boolean offer(final Runnable runnable)
-    {
-        final ReadWriteRunnable job = (ReadWriteRunnable) runnable;
-        final ReentrantLock putLock = _putLock;
-        putLock.lock();
-        try
-        {
-            if(job.isRead())
-            {
-                _readJobQueue.offer(job);
-            }
-            else
-            {
-                _writeJobQueue.offer(job);
-            }
-            if(_count.getAndIncrement() == 0)
-            {
-                _takeLock.lock();
-                try
-                {
-                    _notEmpty.signal();
-                }
-                finally
-                {
-                    _takeLock.unlock();
-                }
-            }
-            return true;
-        }
-        finally
-        {
-            putLock.unlock();
-        }
-    }
-
-    public void put(final Runnable runnable) throws InterruptedException
-    {
-        final ReadWriteRunnable job = (ReadWriteRunnable) runnable;
-        final ReentrantLock putLock = _putLock;
-        putLock.lock();
-
-        try
-        {
-            if(job.isRead())
-            {
-                _readJobQueue.offer(job);
-            }
-            else
-            {
-                _writeJobQueue.offer(job);
-            }
-            if(_count.getAndIncrement() == 0)
-            {
-                                _takeLock.lock();
-                try
-                {
-                    _notEmpty.signal();
-                }
-                finally
-                {
-                    _takeLock.unlock();
-                }
-            }
-
-        }
-        finally
-        {
-            putLock.unlock();
-        }
-    }
-
-
-
-    public boolean offer(final Runnable runnable, final long timeout, final TimeUnit unit) throws InterruptedException
-    {
-        final ReadWriteRunnable job = (ReadWriteRunnable) runnable;
-        final ReentrantLock putLock = _putLock;
-        putLock.lock();
-
-        try
-        {
-            if(job.isRead())
-            {
-                _readJobQueue.offer(job);
-            }
-            else
-            {
-                _writeJobQueue.offer(job);
-            }
-            if(_count.getAndIncrement() == 0)
-            {
-                _takeLock.lock();
-                try
-                {
-                    _notEmpty.signal();
-                }
-                finally
-                {
-                    _takeLock.unlock();
-                }
-            }
-
-            return true;
-        }
-        finally
-        {
-            putLock.unlock();
-        }
-
-    }
-
-    public Runnable take() throws InterruptedException
-    {
-        final ReentrantLock takeLock = _takeLock;
-        takeLock.lockInterruptibly();
-        try
-        {
-            try
-            {
-                while (_count.get() == 0)
-                {
-                    _notEmpty.await();
-                }
-            }
-            catch (InterruptedException ie)
-            {
-                _notEmpty.signal();
-                throw ie;
-            }
-
-            ReadWriteRunnable job = _writeJobQueue.poll();
-            if(job == null)
-            {
-                job = _readJobQueue.poll();
-            }
-            int c = _count.getAndDecrement();
-            if (c > 1)
-            {
-                _notEmpty.signal();
-            }
-            return job;
-        }
-        finally
-        {
-            takeLock.unlock();
-        }
-
-
-    }
-
-    public Runnable poll(final long timeout, final TimeUnit unit) throws InterruptedException
-    {
-        final ReentrantLock takeLock = _takeLock;
-        final AtomicInteger count = _count;
-        long nanos = unit.toNanos(timeout);
-        takeLock.lockInterruptibly();
-        ReadWriteRunnable job = null;
-        try
-        {
-
-            for (;;)
-            {
-                if (count.get() > 0)
-                {
-                    job = _writeJobQueue.poll();
-                    if(job == null)
-                    {
-                        job = _readJobQueue.poll();
-                    }
-                    int c = count.getAndDecrement();
-                    if (c > 1)
-                    {
-                        _notEmpty.signal();
-                    }
-                    break;
-                }
-                if (nanos <= 0)
-                {
-                    return null;
-                }
-                try
-                {
-                    nanos = _notEmpty.awaitNanos(nanos);
-                }
-                catch (InterruptedException ie)
-                {
-                    _notEmpty.signal();
-                    throw ie;
-                }
-            }
-        }
-        finally
-        {
-            takeLock.unlock();
-        }
-
-        return job;
-    }
-
-    public int remainingCapacity()
-    {
-        return Integer.MAX_VALUE;
-    }
-
-    public int drainTo(final Collection<? super Runnable> c)
-    {
-        int total = 0;
-
-        _putLock.lock();
-        _takeLock.lock();
-        try
-        {
-            ReadWriteRunnable job;
-            while((job = _writeJobQueue.peek())!= null)
-            {
-                c.add(job);
-                _writeJobQueue.poll();
-                _count.decrementAndGet();
-                total++;
-            }
-
-            while((job = _readJobQueue.peek())!= null)
-            {
-                c.add(job);
-                _readJobQueue.poll();
-                _count.decrementAndGet();
-                total++;
-            }
-
-        }
-        finally
-        {
-            _takeLock.unlock();
-            _putLock.unlock();
-        }
-        return total;
-    }
-
-    public int drainTo(final Collection<? super Runnable> c, final int maxElements)
-    {
-        int total = 0;
-
-        _putLock.lock();
-        _takeLock.lock();
-        try
-        {
-            ReadWriteRunnable job;
-            while(total<=maxElements && (job = _writeJobQueue.peek())!= null)
-            {
-                c.add(job);
-                _writeJobQueue.poll();
-                _count.decrementAndGet();
-                total++;
-            }
-
-            while(total<=maxElements && (job = _readJobQueue.peek())!= null)
-            {
-                c.add(job);
-                _readJobQueue.poll();
-                _count.decrementAndGet();
-                total++;
-            }
-
-        }
-        finally
-        {
-            _takeLock.unlock();
-            _putLock.unlock();
-        }
-        return total;
-
-    }
-
-    public Runnable poll()
-    {
-        final ReentrantLock takeLock = _takeLock;
-        takeLock.lock();
-        try
-        {
-            if(_count.get() > 0)
-            {
-                ReadWriteRunnable job = _writeJobQueue.poll();
-                if(job == null)
-                {
-                    job = _readJobQueue.poll();
-                }
-                _count.decrementAndGet();
-                return job;
-            }
-            else
-            {
-                return null;
-            }
-        }
-        finally
-        {
-            takeLock.unlock();
-        }
-
-    }
-
-    public Runnable peek()
-    {
-        final ReentrantLock takeLock = _takeLock;
-        takeLock.lock();
-        try
-        {
-            ReadWriteRunnable job = _writeJobQueue.peek();
-            if(job == null)
-            {
-                job = _readJobQueue.peek();
-            }
-            return job;
-        }
-        finally
-        {
-            takeLock.unlock();
-        }
-    }
-}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
deleted file mode 100644
index 140c93c..0000000
--- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.apache.qpid.pool;
-
-/*
-*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*
-*/
-public interface ReadWriteRunnable extends Runnable
-{
-    boolean isRead();
-}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
index 8152a1f..3e99b24 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
@@ -96,8 +96,6 @@
      */
     private ThreadFactory _threadFactory = Executors.defaultThreadFactory();
 
-    private final boolean _useBiasedPool = Boolean.getBoolean("org.apache.qpid.use_write_biased_pool");
-
     /**
      * Retrieves the singleton instance of this reference counter.
      *
@@ -125,26 +123,12 @@
         {
             if (_refCount++ == 0)
             {
-                // Use a job queue that biases to writes
-                if(_useBiasedPool)
-                {
-                    _pool =  new ThreadPoolExecutor(_poolSize, _poolSize,
-                                          0L, TimeUnit.MILLISECONDS,
-                                          new ReadWriteJobQueue(),
-                                          _threadFactory);
-
-                }
-                else
-                {
-                    _pool = new ThreadPoolExecutor(_poolSize, _poolSize,
-                            0L, TimeUnit.MILLISECONDS,
-                            new LinkedBlockingQueue<Runnable>(),
-                            _threadFactory);
-                }
-
+                _pool = new ThreadPoolExecutor(_poolSize, _poolSize,
+                        0L, TimeUnit.MILLISECONDS,
+                        new LinkedBlockingQueue<Runnable>(),
+                        _threadFactory);
             }
 
-
             return _pool;
         }
     }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index b784330..dee5f69 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -383,13 +383,19 @@
 
     public void received(ProtocolEvent event)
     {
-        log.debug("RECV: [%s] %s", this, event);
+        if(log.isDebugEnabled())
+        {
+            log.debug("RECV: [%s] %s", this, event);
+        }
         event.delegate(this, delegate);
     }
 
     public void send(ProtocolEvent event)
     {
-        log.debug("SEND: [%s] %s", this, event);
+        if(log.isDebugEnabled())
+        {
+            log.debug("SEND: [%s] %s", this, event);
+        }
         Sender s = sender;
         if (s == null)
         {
@@ -400,8 +406,15 @@
 
     public void flush()
     {
-        log.debug("FLUSH: [%s]", this);
-        sender.flush();
+        if(log.isDebugEnabled())
+        {
+            log.debug("FLUSH: [%s]", this);
+        }
+        final Sender<ProtocolEvent> theSender = sender;
+        if(theSender != null)
+        {
+            theSender.flush();
+        }
     }
 
     protected void invoke(Method method)
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java
index 9439e5e..543856c 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Header.java
@@ -20,13 +20,7 @@
  */
 package org.apache.qpid.transport;
 
-import org.apache.qpid.transport.network.Frame;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.LinkedHashMap;
-import java.nio.ByteBuffer;
+import java.util.*;
 
 
 /**
@@ -35,45 +29,87 @@
  * @author Rafael H. Schloming
  */
 
-public class Header {
+public class Header
+{
 
-    private final Struct[] structs;
+    private final DeliveryProperties _deliveryProps;
+    private final MessageProperties _messageProps;
+    private final List<Struct> _nonStandardProps;
 
-    public Header(List<Struct> structs)
+    public Header(DeliveryProperties deliveryProps, MessageProperties messageProps)
     {
-        this(structs.toArray(new Struct[structs.size()]));
+        this(deliveryProps, messageProps, null);
     }
 
-    public Header(Struct ... structs)
+    public Header(DeliveryProperties deliveryProps, MessageProperties messageProps, List<Struct> nonStandardProps)
     {
-        this.structs = structs;
+        _deliveryProps = deliveryProps;
+        _messageProps = messageProps;
+        _nonStandardProps = nonStandardProps;
     }
 
     public Struct[] getStructs()
     {
-        return structs;
-    }
-
-
-    public <T> T get(Class<T> klass)
-    {
-        for (Struct st : structs)
+        int size = 0;
+        if(_deliveryProps != null)
         {
-            if (klass.isInstance(st))
+            size++;
+        }
+        if(_messageProps != null)
+        {
+            size++;
+        }
+        if(_nonStandardProps != null)
+        {
+            size+=_nonStandardProps.size();
+        }
+        Struct[] structs = new Struct[size];
+        int index = 0;
+        if(_deliveryProps != null)
+        {
+            structs[index++] = _deliveryProps;
+        }
+        if(_messageProps != null)
+        {
+            structs[index++] = _messageProps;
+        }
+        if(_nonStandardProps != null)
+        {
+            for(Struct struct : _nonStandardProps)
             {
-                return (T) st;
+                structs[index++] = struct;
             }
         }
 
-        return null;
+        return structs;
+    }
+
+    public DeliveryProperties getDeliveryProperties()
+    {
+        return _deliveryProps;
+    }
+
+    public MessageProperties getMessageProperties()
+    {
+        return _messageProps;
+    }
+
+    public List<Struct> getNonStandardProperties()
+    {
+        return _nonStandardProps;
     }
 
     public String toString()
     {
-        StringBuffer str = new StringBuffer();
+        StringBuilder str = new StringBuilder();
         str.append(" Header(");
         boolean first = true;
-        for (Struct s : structs)
+        if(_deliveryProps !=null)
+        {
+            first=false;
+            str.append(_deliveryProps);
+        }
+        if(_messageProps != null)
         {
             if (first)
             {
@@ -83,9 +119,24 @@
             {
                 str.append(", ");
             }
-            str.append(s);
+            str.append(_messageProps);
         }
-        str.append(")");
+        if(_nonStandardProps != null)
+        {
+            for (Struct s : _nonStandardProps)
+            {
+                if (first)
+                {
+                    first = false;
+                }
+                else
+                {
+                    str.append(", ");
+                }
+                str.append(s);
+            }
+        }
+        str.append(')');
         return str.toString();
     }
 
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java
index f4335dc..c47171d 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Range.java
@@ -21,6 +21,8 @@
 package org.apache.qpid.transport;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
 import static org.apache.qpid.util.Serial.*;
@@ -32,94 +34,265 @@
  * @author Rafael H. Schloming
  */
 
-public final class Range
+public abstract class Range implements RangeSet
 {
-    private final int lower;
-    private final int upper;
-
-    public Range(int lower, int upper)
+    public static Range newInstance(int point)
     {
-        this.lower = lower;
-        this.upper = upper;
+        return new PointImpl(point);
     }
 
-    public int getLower()
+    public static Range newInstance(int lower, int upper)
     {
-        return lower;
+        return lower == upper ? new PointImpl(lower) : new RangeImpl(lower, upper);
     }
 
-    public int getUpper()
-    {
-        return upper;
-    }
+    public abstract int getLower();
 
-    public boolean includes(int value)
-    {
-        return le(lower, value) && le(value, upper);
-    }
+    public abstract int getUpper();
 
-    public boolean includes(Range range)
-    {
-        return includes(range.lower) && includes(range.upper);
-    }
+    public abstract boolean includes(int value);
 
-    public boolean intersects(Range range)
-    {
-        return (includes(range.lower) || includes(range.upper) ||
-                range.includes(lower) || range.includes(upper));
-    }
+    public abstract boolean includes(Range range);
 
-    public boolean touches(Range range)
-    {
-        return (intersects(range) ||
-                includes(range.upper + 1) || includes(range.lower - 1) ||
-                range.includes(upper + 1) || range.includes(lower - 1));
-    }
+    public abstract boolean intersects(Range range);
 
-    public Range span(Range range)
-    {
-        return new Range(min(lower, range.lower), max(upper, range.upper));
-    }
+    public abstract boolean touches(Range range);
 
-    public List<Range> subtract(Range range)
-    {
-        List<Range> result = new ArrayList<Range>();
+    public abstract Range span(Range range);
 
-        if (includes(range.lower) && le(lower, range.lower - 1))
-        {
-            result.add(new Range(lower, range.lower - 1));
-        }
+    public abstract List<Range> subtract(Range range);
 
-        if (includes(range.upper) && le(range.upper + 1, upper))
-        {
-            result.add(new Range(range.upper + 1, upper));
-        }
-
-        if (result.isEmpty() && !range.includes(this))
-        {
-            result.add(this);
-        }
-
-        return result;
-    }
 
     public Range intersect(Range range)
     {
-        int l = max(lower, range.lower);
-        int r = min(upper, range.upper);
+        int l = max(getLower(), range.getLower());
+        int r = min(getUpper(), range.getUpper());
         if (gt(l, r))
         {
             return null;
         }
         else
         {
-            return new Range(l, r);
+            return newInstance(l, r);
         }
     }
 
-    public String toString()
+
+
+    public int size()
     {
-        return "[" + lower + ", " + upper + "]";
+        return 1;
     }
 
+    public Iterator<Range> iterator()
+    {
+        return new RangeIterator();
+    }
+
+    public Range getFirst()
+    {
+        return this;
+    }
+
+    public Range getLast()
+    {
+        return this;
+    }
+
+    public void add(Range range)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void add(int lower, int upper)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void add(int value)
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public void clear()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public RangeSet copy()
+    {
+        RangeSet rangeSet = RangeSetFactory.createRangeSet();
+        rangeSet.add(this);
+        return rangeSet;
+    }
+
+    private static class PointImpl extends Range
+    {
+        private final int point;
+
+        private PointImpl(int point)
+        {
+            this.point = point;
+        }
+
+        public int getLower()
+        {
+            return point;
+        }
+
+        public int getUpper()
+        {
+            return point;
+        }
+
+        public boolean includes(int value)
+        {
+            return value == point;
+        }
+
+
+        public boolean includes(Range range)
+        {
+            return range.getLower() == point && range.getUpper() == point;
+        }
+
+        public boolean intersects(Range range)
+        {
+            return range.includes(point);
+        }
+
+        public boolean touches(Range range)
+        {
+            return intersects(range) ||
+                    includes(range.getUpper() + 1) || includes(range.getLower() - 1) ||
+                    range.includes(point + 1) || range.includes(point - 1);
+        }
+
+        public Range span(Range range)
+        {
+            return newInstance(min(point, range.getLower()), max(point, range.getUpper()));
+        }
+
+        public List<Range> subtract(Range range)
+        {
+            if(range.includes(point))
+            {
+                return Collections.emptyList();
+            }
+            else
+            {
+                return Collections.singletonList((Range) this);
+            }
+        }
+
+        public String toString()
+        {
+            return "[" + point + ", " + point + "]";
+        }
+
+
+    }
+
+    private static class RangeImpl extends Range
+    {
+        private final int lower;
+        private final int upper;
+
+        private RangeImpl(int lower, int upper)
+        {
+            this.lower = lower;
+            this.upper = upper;
+        }
+
+        public int getLower()
+        {
+            return lower;
+        }
+
+        public int getUpper()
+        {
+            return upper;
+        }
+
+        public boolean includes(int value)
+        {
+            return le(lower, value) && le(value, upper);
+        }
+
+        public boolean includes(Range range)
+        {
+            return includes(range.getLower()) && includes(range.getUpper());
+        }
+
+        public boolean intersects(Range range)
+        {
+            return (includes(range.getLower()) || includes(range.getUpper()) ||
+                    range.includes(lower) || range.includes(upper));
+        }
+
+        public boolean touches(Range range)
+        {
+            return (intersects(range) ||
+                    includes(range.getUpper() + 1) || includes(range.getLower() - 1) ||
+                    range.includes(upper + 1) || range.includes(lower - 1));
+        }
+
+        public Range span(Range range)
+        {
+            return newInstance(min(lower, range.getLower()), max(upper, range.getUpper()));
+        }
+
+        public List<Range> subtract(Range range)
+        {
+            List<Range> result = new ArrayList<Range>();
+
+            if (includes(range.getLower()) && le(lower, range.getLower() - 1))
+            {
+                result.add(newInstance(lower, range.getLower() - 1));
+            }
+
+            if (includes(range.getUpper()) && le(range.getUpper() + 1, upper))
+            {
+                result.add(newInstance(range.getUpper() + 1, upper));
+            }
+
+            if (result.isEmpty() && !range.includes(this))
+            {
+                result.add(this);
+            }
+
+            return result;
+        }
+
+
+        public String toString()
+        {
+            return "[" + lower + ", " + upper + "]";
+        }
+    }
+
+
+    private class RangeIterator implements Iterator<Range>
+    {
+        private boolean atFirst = true;
+
+        public boolean hasNext()
+        {
+            return atFirst;
+        }
+
+        public Range next()
+        {
+
+            Range range = atFirst ? Range.this : null;
+            atFirst = false;
+            return range;
+        }
+
+
+        public void remove()
+        {
+            throw new UnsupportedOperationException();
+        }
+    }
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
index 3850dc1..34ebd02 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
@@ -20,9 +20,7 @@
  */
 package org.apache.qpid.transport;
 
-import java.util.Iterator;
-import java.util.ListIterator;
-import java.util.LinkedList;
+import java.util.*;
 
 import static org.apache.qpid.util.Serial.*;
 
@@ -32,121 +30,29 @@
  * @author Rafael H. Schloming
  */
 
-public final class RangeSet implements Iterable<Range>
+public interface RangeSet extends Iterable<Range>
 {
 
-    private LinkedList<Range> ranges = new LinkedList<Range>();
+    int size();
 
-    public int size()
-    {
-        return ranges.size();
-    }
+    Iterator<Range> iterator();
 
-    public Iterator<Range> iterator()
-    {
-        return ranges.iterator();
-    }
+    Range getFirst();
 
-    public Range getFirst()
-    {
-        return ranges.getFirst();
-    }
+    Range getLast();
 
-    public Range getLast()
-    {
-        return ranges.getLast();
-    }
+    boolean includes(Range range);
 
-    public boolean includes(Range range)
-    {
-        for (Range r : this)
-        {
-            if (r.includes(range))
-            {
-                return true;
-            }
-        }
+    boolean includes(int n);
 
-        return false;
-    }
+    void add(Range range);
 
-    public boolean includes(int n)
-    {
-        for (Range r : this)
-        {
-            if (r.includes(n))
-            {
-                return true;
-            }
-        }
+    void add(int lower, int upper);
 
-        return false;
-    }
+    void add(int value);
 
-    public void add(Range range)
-    {
-        ListIterator<Range> it = ranges.listIterator();
+    void clear();
 
-        while (it.hasNext())
-        {
-            Range next = it.next();
-            if (range.touches(next))
-            {
-                it.remove();
-                range = range.span(next);
-            }
-            else if (lt(range.getUpper(), next.getLower()))
-            {
-                it.previous();
-                it.add(range);
-                return;
-            }
-        }
-
-        it.add(range);
-    }
-
-    public void add(int lower, int upper)
-    {
-        add(new Range(lower, upper));
-    }
-
-    public void add(int value)
-    {
-        add(value, value);
-    }
-
-    public void clear()
-    {
-        ranges.clear();
-    }
-
-    public RangeSet copy()
-    {
-        RangeSet copy = new RangeSet();
-        copy.ranges.addAll(ranges);
-        return copy;
-    }
-
-    public String toString()
-    {
-        StringBuffer str = new StringBuffer();
-        str.append("{");
-        boolean first = true;
-        for (Range range : ranges)
-        {
-            if (first)
-            {
-                first = false;
-            }
-            else
-            {
-                str.append(", ");
-            }
-            str.append(range);
-        }
-        str.append("}");
-        return str.toString();
-    }
+    RangeSet copy();
 
 }
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetFactory.java
similarity index 68%
copy from qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java
copy to qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetFactory.java
index ec0e8ea..0f19d7e 100644
--- a/qpid/java/client/src/main/java/org/apache/qpid/filter/MessageFilter.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetFactory.java
@@ -1,27 +1,34 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
  * regarding copyright ownership.  The ASF licenses this file
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *   http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
+ *
  */
-package org.apache.qpid.filter;
+package org.apache.qpid.transport;
 
-import org.apache.qpid.client.message.AbstractJMSMessage;
-
-
-public interface MessageFilter
+public class RangeSetFactory
 {
-    boolean matches(AbstractJMSMessage message);
-    String getSelector();
+    public static RangeSet createRangeSet()
+    {
+        return new RangeSetImpl();
+    }
+
+    public static RangeSet createRangeSet(int size)
+    {
+        return new RangeSetImpl(size);
+    }
 }
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetImpl.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetImpl.java
new file mode 100644
index 0000000..f2540af
--- /dev/null
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/RangeSetImpl.java
@@ -0,0 +1,178 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import static org.apache.qpid.util.Serial.lt;
+
+public class RangeSetImpl implements RangeSet
+{
+
+    private List<Range> ranges;
+
+    public RangeSetImpl()
+    {
+        ranges =  new ArrayList<Range>();
+    }
+
+    public RangeSetImpl(int size)
+    {
+        ranges =  new ArrayList<Range>(size);
+    }
+
+
+    public RangeSetImpl(org.apache.qpid.transport.RangeSetImpl copy)
+    {
+        ranges = new ArrayList<Range>(copy.ranges);
+    }
+
+    public int size()
+    {
+        return ranges.size();
+    }
+
+    public Iterator<Range> iterator()
+    {
+        return ranges.iterator();
+    }
+
+    public Range getFirst()
+    {
+        return ranges.get(0);
+    }
+
+    public Range getLast()
+    {
+        return ranges.get(ranges.size() - 1);
+    }
+
+    public boolean includes(Range range)
+    {
+        for (Range r : this)
+        {
+            if (r.includes(range))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean includes(int n)
+    {
+        for (Range r : this)
+        {
+            if (r.includes(n))
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public void add(Range range)
+    {
+        ListIterator<Range> it = ranges.listIterator();
+
+        while (it.hasNext())
+        {
+            Range next = it.next();
+            if (range.touches(next))
+            {
+                it.remove();
+                range = range.span(next);
+            }
+            else if (lt(range.getUpper(), next.getLower()))
+            {
+                it.previous();
+                it.add(range);
+                return;
+            }
+        }
+
+        it.add(range);
+    }
+
+    public void add(int lower, int upper)
+    {
+        switch(ranges.size())
+        {
+            case 0:
+                ranges.add(Range.newInstance(lower, upper));
+                break;
+
+            case 1:
+                Range first = ranges.get(0);
+                if(first.getUpper() + 1 >= lower && upper >= first.getUpper())
+                {
+                    ranges.set(0, Range.newInstance(first.getLower(), upper));
+                    break;
+                }
+
+            default:
+                add(Range.newInstance(lower, upper));
+        }
+
+
+    }
+
+    public void add(int value)
+    {
+        add(value, value);
+    }
+
+    public void clear()
+    {
+        ranges.clear();
+    }
+
+    public RangeSet copy()
+    {
+        return new org.apache.qpid.transport.RangeSetImpl(this);
+    }
+
+    public String toString()
+    {
+        StringBuffer str = new StringBuffer();
+        str.append("{");
+        boolean first = true;
+        for (Range range : ranges)
+        {
+            if (first)
+            {
+                first = false;
+            }
+            else
+            {
+                str.append(", ");
+            }
+            str.append(range);
+        }
+        str.append("}");
+        return str.toString();
+    }
+}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java
index 321e525..5a9ea73 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/Session.java
@@ -44,6 +44,7 @@
 import static org.apache.qpid.util.Strings.toUTF8;
 
 import java.nio.ByteBuffer;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -61,7 +62,7 @@
 public class Session extends SessionInvoker
 {
     private static final Logger log = Logger.get(Session.class);
-
+    
     public enum State { NEW, DETACHED, RESUMING, OPEN, CLOSING, CLOSED }
 
     static class DefaultSessionListener implements SessionListener
@@ -96,6 +97,9 @@
     private final long timeout = Long.getLong(ClientProperties.QPID_SYNC_OP_TIMEOUT,
                                         Long.getLong(ClientProperties.AMQJ_DEFAULT_SYNCWRITE_TIMEOUT,
                                                      ClientProperties.DEFAULT_SYNC_OPERATION_TIMEOUT));
+    private final long blockedSendTimeout = Long.getLong("qpid.flow_control_wait_failure", timeout);
+    private long blockedSendReportingPeriod = Long.getLong("qpid.flow_control_wait_notify_period",5000L);
+
     private boolean autoSync = false;
 
     private boolean incomingInit;
@@ -228,10 +232,21 @@
         {
             try
             {
-                if (!credit.tryAcquire(timeout, TimeUnit.MILLISECONDS))
+                long wait = blockedSendTimeout > blockedSendReportingPeriod ? blockedSendReportingPeriod :
+                           blockedSendTimeout;
+                long totalWait = 1L;
+                while(totalWait <= blockedSendTimeout && !credit.tryAcquire(wait, TimeUnit.MILLISECONDS))
                 {
+                    totalWait+=wait;
+                    log.warn("Message send delayed by " + (totalWait)/1000 + "s due to broker enforced flow control");
+
+
+                }
+                if(totalWait > blockedSendTimeout)
+                {
+                    log.error("Message send failed due to timeout waiting on broker enforced flow control");
                     throw new SessionException
-                        ("timed out waiting for message credit");
+                            ("timed out waiting for message credit");
                 }
             }
             catch (InterruptedException e)
@@ -247,7 +262,7 @@
         synchronized (processedLock)
         {
             incomingInit = false;
-            processed = new RangeSet();
+            processed = RangeSetFactory.createRangeSet();
         }
     }
 
@@ -276,22 +291,22 @@
                 else if (m instanceof MessageTransfer)
                 {
                 	MessageTransfer xfr = (MessageTransfer)m;
-                	
-                	if (xfr.getHeader() != null)
+
+                    Header header = xfr.getHeader();
+
+                    if (header != null)
                 	{
-                		if (xfr.getHeader().get(DeliveryProperties.class) != null)
+                		if (header.getDeliveryProperties() != null)
                 		{
-                		   xfr.getHeader().get(DeliveryProperties.class).setRedelivered(true);
+                		   header.getDeliveryProperties().setRedelivered(true);
                 		}
                 		else
                 		{
-                			Struct[] structs = xfr.getHeader().getStructs();
                 			DeliveryProperties deliveryProps = new DeliveryProperties();
                     		deliveryProps.setRedelivered(true);
-                    		
-                    		List<Struct> list = Arrays.asList(structs);
-                    		list.add(deliveryProps);
-                    		xfr.setHeader(new Header(list));
+
+                    		xfr.setHeader(new Header(deliveryProps, header.getMessageProperties(),
+                                                     header.getNonStandardProperties()));
                 		}
                 		
                 	}
@@ -299,7 +314,7 @@
                 	{
                 		DeliveryProperties deliveryProps = new DeliveryProperties();
                 		deliveryProps.setRedelivered(true);
-                		xfr.setHeader(new Header(deliveryProps));
+                		xfr.setHeader(new Header(deliveryProps, null, null));
                 	}
                 }
                 sessionCommandPoint(m.getId(), 0);
@@ -394,38 +409,46 @@
 
     public void processed(int command)
     {
-        processed(new Range(command, command));
-    }
-
-    public void processed(int lower, int upper)
-    {
-
-        processed(new Range(lower, upper));
+        processed(command, command);
     }
 
     public void processed(Range range)
     {
-        log.debug("%s processed(%s) %s %s", this, range, syncPoint, maxProcessed);
+
+        processed(range.getLower(), range.getUpper());
+    }
+
+    public void processed(int lower, int upper)
+    {
+        if(log.isDebugEnabled())
+        {
+            log.debug("%s processed([%d,%d]) %s %s", this, lower, upper, syncPoint, maxProcessed);
+        }
 
         boolean flush;
         synchronized (processedLock)
         {
-            log.debug("%s", processed);
-
-            if (ge(range.getUpper(), commandsIn))
+            if(log.isDebugEnabled())
             {
-                throw new IllegalArgumentException
-                    ("range exceeds max received command-id: " + range);
+                log.debug("%s", processed);
             }
 
-            processed.add(range);
-            Range first = processed.getFirst();
-            int lower = first.getLower();
-            int upper = first.getUpper();
-            int old = maxProcessed;
-            if (le(lower, maxProcessed + 1))
+            if (ge(upper, commandsIn))
             {
-                maxProcessed = max(maxProcessed, upper);
+                throw new IllegalArgumentException
+                    ("range exceeds max received command-id: " + Range.newInstance(lower, upper));
+            }
+
+            processed.add(lower, upper);
+
+            Range first = processed.getFirst();
+
+            int flower = first.getLower();
+            int fupper = first.getUpper();
+            int old = maxProcessed;
+            if (le(flower, maxProcessed + 1))
+            {
+                maxProcessed = max(maxProcessed, fupper);
             }
             boolean synced = ge(maxProcessed, syncPoint);
             flush = lt(old, syncPoint) && synced;
@@ -442,7 +465,7 @@
 
     void flushExpected()
     {
-        RangeSet rs = new RangeSet();
+        RangeSet rs = RangeSetFactory.createRangeSet();
         synchronized (processedLock)
         {
             if (incomingInit)
@@ -478,7 +501,7 @@
     {
         synchronized (processedLock)
         {
-            RangeSet newProcessed = new RangeSet();
+            RangeSet newProcessed = RangeSetFactory.createRangeSet();
             for (Range pr : processed)
             {
                 for (Range kr : kc)
@@ -534,7 +557,12 @@
             {
                 maxComplete = max(maxComplete, upper);
             }
-            log.debug("%s   commands remaining: %s", this, commandsOut - maxComplete);
+
+            if(log.isDebugEnabled())
+            {
+                log.debug("%s   commands remaining: %s", this, commandsOut - maxComplete);
+            }
+
             commands.notifyAll();
             return gt(maxComplete, old);
         }
@@ -801,8 +829,17 @@
             Waiter w = new Waiter(commands, timeout);
             while (w.hasTime() && state != CLOSED && lt(maxComplete, point))
             {
-                checkFailoverRequired("Session sync was interrupted by failover.");
-                log.debug("%s   waiting for[%d]: %d, %s", this, point, maxComplete, commands);
+                checkFailoverRequired("Session sync was interrupted by failover.");                               
+                if(log.isDebugEnabled())
+                {
+                    List<Method> waitingFor =
+                            Arrays.asList(commands)
+                                  .subList(mod(maxComplete,commands.length),
+                                           mod(commandsOut-1, commands.length) < mod(maxComplete, commands.length)
+                                             ? commands.length-1
+                                             : mod(commandsOut-1, commands.length));
+                    log.debug("%s   waiting for[%d]: %d, %s", this, point, maxComplete, waitingFor);
+                }
                 w.await();
             }
 
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
index 3341149..028b912 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
@@ -91,21 +91,38 @@
     {
         RangeSet ranges = cmp.getCommands();
         RangeSet known = null;
-        if (cmp.getTimelyReply())
-        {
-            known = new RangeSet();
-        }
 
         if (ranges != null)
         {
-            for (Range range : ranges)
+            if(ranges.size() == 1)
             {
+                Range range = ranges.getFirst();
                 boolean advanced = ssn.complete(range.getLower(), range.getUpper());
-                if (advanced && known != null)
+
+                if(advanced && cmp.getTimelyReply())
                 {
-                    known.add(range);
+                    known = range;
                 }
             }
+            else
+            {
+                if (cmp.getTimelyReply())
+                {
+                    known = RangeSetFactory.createRangeSet();
+                }
+                for (Range range : ranges)
+                {
+                    boolean advanced = ssn.complete(range.getLower(), range.getUpper());
+                    if (advanced && known != null)
+                    {
+                        known.add(range);
+                    }
+                }
+            }
+        }
+        else if (cmp.getTimelyReply())
+        {
+            known = RangeSetFactory.createRangeSet();
         }
 
         if (known != null)
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java
index 09ce6a7..6ff3b21 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractDecoder.java
@@ -29,12 +29,7 @@
 import java.util.Map;
 import java.util.UUID;
 
-import org.apache.qpid.transport.Binary;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Struct;
-import org.apache.qpid.transport.Type;
-
-import static org.apache.qpid.transport.util.Functions.*;
+import org.apache.qpid.transport.*;
 
 
 /**
@@ -194,18 +189,19 @@
     public RangeSet readSequenceSet()
     {
         int count = readUint16()/8;
-        if (count == 0)
+        switch(count)
         {
-            return null;
-        }
-        else
-        {
-            RangeSet ranges = new RangeSet();
-            for (int i = 0; i < count; i++)
-            {
-                ranges.add(readSequenceNo(), readSequenceNo());
-            }
-            return ranges;
+            case 0:
+                return null;
+            case 1:
+                return Range.newInstance(readSequenceNo(), readSequenceNo());
+            default:
+                RangeSet ranges = RangeSetFactory.createRangeSet(count);
+                for (int i = 0; i < count; i++)
+                {
+                    ranges.add(readSequenceNo(), readSequenceNo());
+                }
+                return ranges;
         }
     }
 
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
index 4486b03..d9150be 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
@@ -70,6 +70,16 @@
         return slice;
     }
 
+    public int position()
+    {
+        return out.position();
+    }
+
+    public ByteBuffer underlyingBuffer()
+    {
+        return out;
+    }
+
     private void grow(int size)
     {
         ByteBuffer old = out;
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
index 1a85ab8..8cd5c29 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
@@ -26,13 +26,7 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.qpid.transport.Header;
-import org.apache.qpid.transport.Method;
-import org.apache.qpid.transport.ProtocolError;
-import org.apache.qpid.transport.ProtocolEvent;
-import org.apache.qpid.transport.ProtocolHeader;
-import org.apache.qpid.transport.Receiver;
-import org.apache.qpid.transport.Struct;
+import org.apache.qpid.transport.*;
 import org.apache.qpid.transport.codec.BBDecoder;
 
 /**
@@ -198,12 +192,33 @@
             break;
         case HEADER:
             command = getIncompleteCommand(channel);
-            List<Struct> structs = new ArrayList<Struct>(2);
+            List<Struct> structs = null;
+            DeliveryProperties deliveryProps = null;
+            MessageProperties messageProps = null;
+
             while (dec.hasRemaining())
             {
-                structs.add(dec.readStruct32());
+                Struct struct = dec.readStruct32();
+                if(struct instanceof  DeliveryProperties && deliveryProps == null)
+                {
+                    deliveryProps = (DeliveryProperties) struct;
+                }
+                else if(struct instanceof MessageProperties && messageProps == null)
+                {
+                    messageProps = (MessageProperties) struct;
+                }
+                else
+                {
+                    if(structs == null)
+                    {
+                        structs = new ArrayList<Struct>(2);
+                    }
+                    structs.add(struct);
+                }
+
             }
-            command.setHeader(new Header(structs));
+            command.setHeader(new Header(deliveryProps,messageProps,structs));
+
             if (frame.isLastSegment())
             {
                 setIncompleteCommand(channel, null);
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
index 685034d..6ac9df9 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
@@ -87,27 +87,35 @@
         }
     }
 
+    private final ByteBuffer _frameHeader = ByteBuffer.allocate(HEADER_SIZE);
+
+    {
+        _frameHeader.order(ByteOrder.BIG_ENDIAN);
+    }
+
     private void frame(byte flags, byte type, byte track, int channel, int size, ByteBuffer buf)
     {
         synchronized (sendlock)
         {
-            ByteBuffer data = ByteBuffer.allocate(size + HEADER_SIZE);
-            data.order(ByteOrder.BIG_ENDIAN);
+            ByteBuffer data = _frameHeader;
+            _frameHeader.rewind();
+
             
             data.put(0, flags);
             data.put(1, type);
             data.putShort(2, (short) (size + HEADER_SIZE));
             data.put(5, track);
             data.putShort(6, (short) channel);
-            data.position(HEADER_SIZE);
+
 
             int limit = buf.limit();
             buf.limit(buf.position() + size);
-            data.put(buf);
-            buf.limit(limit);
- 
+
             data.rewind();
             sender.send(data);
+            sender.send(buf);
+            buf.limit(limit);
+
         }
     }
 
@@ -179,7 +187,7 @@
             }
         }
         method.write(enc);
-        ByteBuffer methodSeg = enc.segment();
+        int methodLimit = enc.position();
 
         byte flags = FIRST_SEG;
 
@@ -189,29 +197,44 @@
             flags |= LAST_SEG;
         }
 
-        ByteBuffer headerSeg = null;
+        int headerLimit = -1;
         if (payload)
         {
             final Header hdr = method.getHeader();
             if (hdr != null)
             {
-                final Struct[] structs = hdr.getStructs();
-
-                for (Struct st : structs)
+                if(hdr.getDeliveryProperties() != null)
                 {
-                    enc.writeStruct32(st);
+                    enc.writeStruct32(hdr.getDeliveryProperties());
+                }
+                if(hdr.getMessageProperties() != null)
+                {
+                    enc.writeStruct32(hdr.getMessageProperties());
+                }
+                if(hdr.getNonStandardProperties() != null)
+                {
+                    for (Struct st : hdr.getNonStandardProperties())
+                    {
+                        enc.writeStruct32(st);
+                    }
                 }
             }
-            headerSeg = enc.segment();
+            headerLimit = enc.position();
         }
 
         synchronized (sendlock)
         {
-            fragment(flags, type, method, methodSeg);
+            ByteBuffer buf = enc.underlyingBuffer();
+            buf.position(0);
+            buf.limit(methodLimit);
+
+            fragment(flags, type, method, buf);
             if (payload)
             {
                 ByteBuffer body = method.getBody();
-                fragment(body == null ? LAST_SEG : 0x0, SegmentType.HEADER, method, headerSeg);
+                buf.limit(headerLimit);
+                buf.position(methodLimit);
+                fragment(body == null ? LAST_SEG : 0x0, SegmentType.HEADER, method, buf);
                 if (body != null)
                 {
                     fragment(LAST_SEG, SegmentType.BODY, method, body);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ByteBufferInputStream.java b/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java
similarity index 86%
rename from qpid/java/broker/src/main/java/org/apache/qpid/server/util/ByteBufferInputStream.java
rename to qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java
index 898a667..b72b342 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/ByteBufferInputStream.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/util/ByteBufferInputStream.java
@@ -18,12 +18,15 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.util;
+package org.apache.qpid.util;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 
+/**
+ * Wraps @link {@link ByteBuffer} into {@link InputStream}
+ */
 public class ByteBufferInputStream extends InputStream
 {
     private final ByteBuffer _buffer;
@@ -36,13 +39,20 @@
     @Override
     public int read() throws IOException
     {
-        return _buffer.get() & 0xFF;
+        if (_buffer.hasRemaining())
+        {
+            return _buffer.get() & 0xFF;
+        }
+        return -1;
     }
 
-
     @Override
     public int read(byte[] b, int off, int len) throws IOException
     {
+        if (!_buffer.hasRemaining())
+        {
+            return -1;
+        }
         if(_buffer.remaining() < len)
         {
             len = _buffer.remaining();
@@ -73,9 +83,7 @@
     @Override
     public long skip(long n) throws IOException
     {
-
         _buffer.position(_buffer.position()+(int)n);
-
         return n;
     }
 
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java b/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
index bd189fe..cb9a946 100644
--- a/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
+++ b/qpid/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
@@ -581,10 +581,10 @@
 
         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.setDouble("double", Double.MAX_VALUE);
+        table.setFloat("float", Float.MAX_VALUE);
         table.setShort("short", Short.MAX_VALUE);
         table.setString("string", "hello");
         table.setString("null-string", null);
@@ -823,9 +823,7 @@
      */
     public void testCheckPropertyNamehasMaxLength()
     {
-        String oldVal = System.getProperty("STRICT_AMQP");
-        System.setProperty("STRICT_AMQP", "true");
-        FieldTable table = new FieldTable();
+        FieldTable table = new FieldTable(true);
 
         StringBuffer longPropertyName = new StringBuffer(129);
 
@@ -845,14 +843,6 @@
         }
         // so length should be zero
         Assert.assertEquals(0, table.getEncodedSize());
-        if (oldVal != null)
-        {
-            System.setProperty("STRICT_AMQP", oldVal);
-        }
-        else
-        {
-            System.clearProperty("STRICT_AMQP");
-        }
     }
 
     /**
@@ -860,9 +850,7 @@
      */
     public void testCheckPropertyNameStartCharacterIsLetter()
     {
-        String oldVal = System.getProperty("STRICT_AMQP");
-        System.setProperty("STRICT_AMQP", "true");
-        FieldTable table = new FieldTable();
+        FieldTable table = new FieldTable(true);
 
         // Try a name that starts with a number
         try
@@ -876,14 +864,6 @@
         }
         // so length should be zero
         Assert.assertEquals(0, table.getEncodedSize());
-        if (oldVal != null)
-        {
-            System.setProperty("STRICT_AMQP", oldVal);
-        }
-        else
-        {
-            System.clearProperty("STRICT_AMQP");
-        }
     }
 
     /**
@@ -891,9 +871,7 @@
      */
     public void testCheckPropertyNameStartCharacterIsHashorDollar()
     {
-        String oldVal = System.getProperty("STRICT_AMQP");
-        System.setProperty("STRICT_AMQP", "true");
-        FieldTable table = new FieldTable();
+        FieldTable table = new FieldTable(true);
 
         // Try a name that starts with a number
         try
@@ -906,14 +884,6 @@
             fail("property name are allowed to start with # and $s");
         }
 
-        if (oldVal != null)
-        {
-            System.setProperty("STRICT_AMQP", oldVal);
-        }
-        else
-        {
-            System.clearProperty("STRICT_AMQP");
-        }
     }
 
     /**
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java b/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java
index ad45d00..889250e 100644
--- a/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java
+++ b/qpid/java/common/src/test/java/org/apache/qpid/transport/RangeSetTest.java
@@ -60,7 +60,7 @@
 
     public void test1()
     {
-        RangeSet ranges = new RangeSet();
+        RangeSet ranges = RangeSetFactory.createRangeSet();
         ranges.add(5, 10);
         check(ranges);
         ranges.add(15, 20);
@@ -77,7 +77,7 @@
 
     public void test2()
     {
-        RangeSet rs = new RangeSet();
+        RangeSet rs = RangeSetFactory.createRangeSet();
         check(rs);
 
         rs.add(1);
@@ -128,7 +128,7 @@
 
     public void testAddSelf()
     {
-        RangeSet a = new RangeSet();
+        RangeSet a = RangeSetFactory.createRangeSet();
         a.add(0, 8);
         check(a);
         a.add(0, 8);
@@ -141,8 +141,8 @@
 
     public void testIntersect1()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(9, 20);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(9, 20);
         Range i1 = a.intersect(b);
         Range i2 = b.intersect(a);
         assertEquals(i1.getUpper(), 10);
@@ -153,16 +153,16 @@
 
     public void testIntersect2()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(11, 20);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(11, 20);
         assertNull(a.intersect(b));
         assertNull(b.intersect(a));
     }
 
     public void testIntersect3()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(3, 5);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(3, 5);
         Range i1 = a.intersect(b);
         Range i2 = b.intersect(a);
         assertEquals(i1.getUpper(), 5);
@@ -173,14 +173,14 @@
 
     public void testSubtract1()
     {
-        Range a = new Range(0, 10);
+        Range a = Range.newInstance(0, 10);
         assertTrue(a.subtract(a).isEmpty());
     }
 
     public void testSubtract2()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(20, 30);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(20, 30);
         List<Range> ranges = a.subtract(b);
         assertEquals(ranges.size(), 1);
         Range d = ranges.get(0);
@@ -190,8 +190,8 @@
 
     public void testSubtract3()
     {
-        Range a = new Range(20, 30);
-        Range b = new Range(0, 10);
+        Range a = Range.newInstance(20, 30);
+        Range b = Range.newInstance(0, 10);
         List<Range> ranges = a.subtract(b);
         assertEquals(ranges.size(), 1);
         Range d = ranges.get(0);
@@ -201,8 +201,8 @@
 
     public void testSubtract4()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(3, 5);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(3, 5);
         List<Range> ranges = a.subtract(b);
         assertEquals(ranges.size(), 2);
         Range low = ranges.get(0);
@@ -215,8 +215,8 @@
 
     public void testSubtract5()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(3, 20);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(3, 20);
         List<Range> ranges = a.subtract(b);
         assertEquals(ranges.size(), 1);
         Range d = ranges.get(0);
@@ -226,8 +226,8 @@
 
     public void testSubtract6()
     {
-        Range a = new Range(0, 10);
-        Range b = new Range(-10, 5);
+        Range a = Range.newInstance(0, 10);
+        Range b = Range.newInstance(-10, 5);
         List<Range> ranges = a.subtract(b);
         assertEquals(ranges.size(), 1);
         Range d = ranges.get(0);
diff --git a/qpid/java/common/src/test/java/org/apache/qpid/util/ByteBufferInputStreamTest.java b/qpid/java/common/src/test/java/org/apache/qpid/util/ByteBufferInputStreamTest.java
new file mode 100644
index 0000000..0b393a4
--- /dev/null
+++ b/qpid/java/common/src/test/java/org/apache/qpid/util/ByteBufferInputStreamTest.java
@@ -0,0 +1,111 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class ByteBufferInputStreamTest extends TestCase
+{
+    private byte[] _data = {2, 1, 5, 3, 4};
+    private ByteBufferInputStream _inputStream;
+
+    public void setUp() throws Exception
+    {
+        _inputStream = new ByteBufferInputStream(ByteBuffer.wrap(_data));
+    }
+
+    public void testRead() throws IOException
+    {
+        for (int i = 0; i < _data.length; i++)
+        {
+            assertEquals("Unexpected byte at position " + i, _data[i], _inputStream.read());
+        }
+        assertEquals("EOF not reached", -1, _inputStream.read());
+    }
+
+    public void testReadByteArray() throws IOException
+    {
+        byte[] readBytes = new byte[_data.length];
+        int length = _inputStream.read(readBytes, 0, 2);
+
+        byte[] expected = new byte[_data.length];
+        System.arraycopy(_data, 0, expected, 0, 2);
+
+        assertTrue("Unexpected data", Arrays.equals(expected, readBytes));
+        assertEquals("Unexpected length", 2, length);
+
+        length = _inputStream.read(readBytes, 2, 3);
+
+        assertTrue("Unexpected data", Arrays.equals(_data, readBytes));
+        assertEquals("Unexpected length", 3, length);
+
+        length = _inputStream.read(readBytes);
+        assertEquals("EOF not reached", -1, length);
+    }
+
+    public void testSkip() throws IOException
+    {
+        _inputStream.skip(3);
+        byte[] readBytes = new byte[_data.length - 3];
+        int length = _inputStream.read(readBytes);
+
+        byte[] expected = new byte[_data.length - 3];
+        System.arraycopy(_data, 3, expected, 0, _data.length - 3);
+
+        assertTrue("Unexpected data", Arrays.equals(expected, readBytes));
+        assertEquals("Unexpected length", _data.length - 3, length);
+    }
+
+    public void testAvailable() throws IOException
+    {
+        int available = _inputStream.available();
+        assertEquals("Unexpected number of available bytes", _data.length, available);
+        byte[] readBytes = new byte[_data.length];
+        _inputStream.read(readBytes);
+        available = _inputStream.available();
+        assertEquals("Unexpected number of available bytes", 0, available);
+    }
+
+    public void testMarkReset() throws IOException
+    {
+        _inputStream.mark(0);
+        byte[] readBytes = new byte[_data.length];
+        int length = _inputStream.read(readBytes);
+        assertEquals("Unexpected length", _data.length, length);
+        assertEquals("Unexpected number of available bytes", 0, _inputStream.available());
+
+        _inputStream.reset();
+        readBytes = new byte[_data.length];
+        length = _inputStream.read(readBytes);
+        assertEquals("Unexpected length", _data.length, length);
+        assertEquals("Unexpected number of available bytes", 0, _inputStream.available());
+    }
+
+    public void testMarkSupported() throws IOException
+    {
+        assertTrue("Unexpected mark supported", _inputStream.markSupported());
+    }
+
+}
diff --git a/qpid/java/common/templates/method/version/MethodBodyClass.vm b/qpid/java/common/templates/method/version/MethodBodyClass.vm
index ce8a453..0e444b8 100644
--- a/qpid/java/common/templates/method/version/MethodBodyClass.vm
+++ b/qpid/java/common/templates/method/version/MethodBodyClass.vm
@@ -46,8 +46,9 @@
  
 package org.apache.qpid.framing.amqp_$version.getMajor()_$version.getMinor();
 
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
+import java.io.DataInput;
+import org.apache.qpid.codec.MarkableDataInput;
+import java.io.DataOutput;
 import java.io.IOException;
 import java.util.HashMap;
 
@@ -58,7 +59,7 @@
 {
     private static final AMQMethodBodyInstanceFactory FACTORY_INSTANCE = new AMQMethodBodyInstanceFactory()
     {
-        public AMQMethodBody newInstance(DataInputStream in, long size) throws AMQFrameDecodingException, IOException
+        public AMQMethodBody newInstance(MarkableDataInput in, long size) throws AMQFrameDecodingException, IOException
         {
             return new ${javaClassName}(in);
         }
@@ -86,7 +87,7 @@
     
     // Constructor
 
-    public ${javaClassName}(DataInputStream buffer) throws AMQFrameDecodingException, IOException
+    public ${javaClassName}(MarkableDataInput buffer) throws AMQFrameDecodingException, IOException
     {
 #foreach( $field in $method.ConsolidatedFields )
         _$field.Name = read$field.getEncodingType()( buffer );
@@ -171,7 +172,7 @@
         return size;        
     }
 
-    public void writeMethodPayload(DataOutputStream buffer) throws IOException
+    public void writeMethodPayload(DataOutput buffer) throws IOException
     {
 #foreach( $field in $method.ConsolidatedFields )
         write$field.getEncodingType()( buffer, _$field.Name );
diff --git a/qpid/java/common/templates/model/MethodRegistryClass.vm b/qpid/java/common/templates/model/MethodRegistryClass.vm
index 8258175..f8a55f2 100644
--- a/qpid/java/common/templates/model/MethodRegistryClass.vm
+++ b/qpid/java/common/templates/model/MethodRegistryClass.vm
@@ -30,10 +30,10 @@
  
 package org.apache.qpid.framing;
 
-import java.io.DataInputStream;
 import java.io.IOException;
 
 import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
+import org.apache.qpid.codec.MarkableDataInput;
 
 import java.util.Map;
 import java.util.HashMap;
@@ -54,7 +54,7 @@
 #end
  			
 			
-    public abstract AMQMethodBody convertToBody(DataInputStream in, long size)
+    public abstract AMQMethodBody convertToBody(MarkableDataInput in, long size)
         throws AMQFrameDecodingException, IOException;
 
     public abstract int getMaxClassId();
diff --git a/qpid/java/common/templates/model/version/MethodRegistryClass.vm b/qpid/java/common/templates/model/version/MethodRegistryClass.vm
index 79553f7..ab5db0e 100644
--- a/qpid/java/common/templates/model/version/MethodRegistryClass.vm
+++ b/qpid/java/common/templates/model/version/MethodRegistryClass.vm
@@ -35,10 +35,10 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.DataInputStream;
 import java.io.IOException;
 
 import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
+import org.apache.qpid.codec.MarkableDataInput;
 
 
 public class MethodRegistry_$version.getMajor()_$version.getMinor() extends MethodRegistry
@@ -87,7 +87,7 @@
     }
 
 
-    public AMQMethodBody convertToBody(DataInputStream in, long size)
+    public AMQMethodBody convertToBody(MarkableDataInput in, long size)
         throws AMQFrameDecodingException, IOException
     {
         int classId = in.readUnsignedShort();
diff --git a/qpid/java/jca/example/qpid-jca-example-properties.xml b/qpid/java/jca/example/qpid-jca-example-properties.xml
index ee0478a..076e5dc 100644
--- a/qpid/java/jca/example/qpid-jca-example-properties.xml
+++ b/qpid/java/jca/example/qpid-jca-example-properties.xml
@@ -49,17 +49,17 @@
          value="responder.Queue;{create:always, node:{type:queue, x-declare:{auto-delete:true}}}"/>
 
     <property name="qpid.hello.topic.dest.address.BURL"
-            value="topic://amq.topic//hello.jcaTopic?routingKey='hello.jcaTopic',autodelete='true'"/>
+            value="BURL:topic://amq.topic//hello.jcaTopic?routingKey='hello.jcaTopic',autodelete='true'"/>
     <property name="qpid.goodbye.topic.dest.address.BURL"
-            value="topic://amq.topic//goodbye.jcaTopic?routingKey='goodbye.jcaTopic',autodelete='true'"/>
+            value="BURL:topic://amq.topic//goodbye.jcaTopic?routingKey='goodbye.jcaTopic',autodelete='true'"/>
     <property name="qpid.hellogoodbye.topic.dest.address.BURL"
-           value="topic://amq.topic//#.jcaTopic"/>
+           value="BURL:topic://amq.topic//#.jcaTopic"/>
     <property name="qpid.hello.queue.dest.address.BURL"
-           value="direct://amq.direct//hello.Queue?routingkey='hello.Queue'"/>
+           value="BURL:direct://amq.direct//hello.Queue?routingkey='hello.Queue'"/>
     <property name="qpid.goodbye.queue.dest.address.BURL"
-           value="direct://amq.direct//goodbye.Queue?routingkey='goodbye.Queue'"/>
+           value="BURL:direct://amq.direct//goodbye.Queue?routingkey='goodbye.Queue'"/>
     <property name="qpid.responder.queue.dest.address.BURL"
-           value="direct://amq.direct//responder.Queue?routingkey='responder.Queue'"/>
+           value="BURL:direct://amq.direct//responder.Queue?routingkey='responder.Queue'"/>
 
     <!-- This macro allows us to construct a property name which contains a property expansion -->
     <macrodef name="set-address-property">
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
index fb1b7f0..53896d8 100644
--- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAManagedConnection.java
@@ -57,6 +57,8 @@
 import javax.transaction.TransactionManager;
 import javax.transaction.xa.XAResource;
 
+import org.apache.qpid.client.Closeable;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -752,26 +754,25 @@
 
       try
       {
-         boolean transacted = _cri.isTransacted();
-         int acknowledgeMode =  Session.AUTO_ACKNOWLEDGE;
-         boolean localTx = _mcf.getUseLocalTx();
+         boolean transacted = _cri.isTransacted() || _mcf.getUseLocalTx();
+         int acknowledgeMode =  (transacted) ? Session.SESSION_TRANSACTED : _cri.getAcknowledgeMode();
 
          if (_cri.getType() == QpidRAConnectionFactory.TOPIC_CONNECTION)
          {
             if (_userName != null && _password != null)
             {
-               if(!localTx)
+               if(!transacted)
                {
                     _connection = _mcf.getCleanAMQConnectionFactory().createXATopicConnection(_userName, _password);
                }
                else
                {
-                    _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection();
+                    _connection = _mcf.getCleanAMQConnectionFactory().createTopicConnection(_userName, _password);
                }
             }
             else
             {
-               if(!localTx)
+               if(!transacted)
                {
                    _connection = _mcf.getDefaultAMQConnectionFactory().createXATopicConnection();
                }
@@ -781,32 +782,31 @@
                }
             }
 
-            if(!localTx)
+            if(!transacted)
             {
                 _xaSession = ((XATopicConnection)_connection).createXATopicSession();
-
             }
             else
             {
-                _session =  ((TopicConnection)_connection).createTopicSession(localTx, acknowledgeMode);
+                _session =  ((TopicConnection)_connection).createTopicSession(transacted, acknowledgeMode);
             }
          }
          else if (_cri.getType() == QpidRAConnectionFactory.QUEUE_CONNECTION)
          {
             if (_userName != null && _password != null)
             {
-               if(!localTx)
+               if(!transacted)
                {
                     _connection = _mcf.getCleanAMQConnectionFactory().createXAQueueConnection(_userName, _password);
                }
                else
                {
-                    _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection();
+                    _connection = _mcf.getCleanAMQConnectionFactory().createQueueConnection(_userName, _password);
                }
             }
             else
             {
-               if(!localTx)
+               if(!transacted)
                {
                    _connection = _mcf.getDefaultAMQConnectionFactory().createXAQueueConnection();
                }
@@ -816,14 +816,14 @@
                }
             }
 
-            if(!localTx)
+            if(!transacted)
             {
                 _xaSession = ((XAQueueConnection)_connection).createXAQueueSession();
 
             }
             else
             {
-               _session =  ((QueueConnection)_connection).createQueueSession(localTx, acknowledgeMode);
+               _session =  ((QueueConnection)_connection).createQueueSession(transacted, acknowledgeMode);
 
             }
          }
@@ -831,18 +831,18 @@
          {
             if (_userName != null && _password != null)
             {
-               if(!localTx)
+               if(!transacted)
                {
                     _connection = _mcf.getCleanAMQConnectionFactory().createXAConnection(_userName, _password);
                }
                else
                {
-                    _connection = _mcf.getCleanAMQConnectionFactory().createConnection();
+                    _connection = _mcf.getCleanAMQConnectionFactory().createConnection(_userName, _password);
                }
             }
             else
             {
-               if(!localTx)
+               if(!transacted)
                {
                    _connection = _mcf.getDefaultAMQConnectionFactory().createXAConnection();
                }
@@ -852,22 +852,24 @@
                }
             }
 
-            if(!localTx)
+            if(!transacted)
             {
                 _xaSession = ((XAQueueConnection)_connection).createXASession();
 
             }
             else
             {
-               _session =  ((QueueConnection)_connection).createSession(localTx, acknowledgeMode);
+               _session =  ((QueueConnection)_connection).createSession(transacted, acknowledgeMode);
 
             }
          }
 
         _connection.setExceptionListener(this);
+
       }
       catch (JMSException je)
       {
+         _log.error(je.getMessage(), je);
          throw new ResourceException(je.getMessage(), je);
       }
    }
@@ -877,4 +879,9 @@
       this._inManagedTx = inManagedTx;
    }
 
+   public boolean isConnectionClosed()
+   {
+       Closeable c = (Closeable)_connection;
+       return (c == null || c.isClosed() || c.isClosing());
+   }
 }
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
index 691fe8c..295a453 100644
--- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRAMessage.java
@@ -71,7 +71,7 @@
          _log.trace("acknowledge()");
       }
 
-      _session.getSession(); // Check for closed
+      _session.getSessionInternal(); // Check for closed
       _message.acknowledge();
    }
 
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
index a270253..fdd4888 100644
--- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/QpidRASessionImpl.java
@@ -410,19 +410,24 @@
       lock();
       try
       {
-         Session session = getSessionInternal();
 
          if (_cri.isTransacted() == false)
          {
             throw new IllegalStateException("Session is not transacted");
          }
 
+         if(_lockedMC.isConnectionClosed())
+         {
+             throw new IllegalStateException("Attempting to call commit when the underlying connection has been closed.");
+         }
+
          if (_log.isTraceEnabled())
          {
             _log.trace("Commit session " + this);
          }
 
-         session.commit();
+         getSessionInternal().commit();
+
       }
       finally
       {
diff --git a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
index 98427d7..57edec8 100644
--- a/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
+++ b/qpid/java/jca/src/main/java/org/apache/qpid/ra/inflow/QpidActivation.java
@@ -113,6 +113,9 @@
    // Whether we are in the failure recovery loop
    private AtomicBoolean _inFailure = new AtomicBoolean(false);
 
+   //Whether or not we have completed activating
+   private AtomicBoolean _activated = new AtomicBoolean(false);
+
    static
    {
       try
@@ -242,7 +245,7 @@
          _log.trace("start()");
       }
       _deliveryActive.set(true);
-      _ra.getWorkManager().scheduleWork(new SetupActivation());
+      new Thread(new SetupActivation()).start();
    }
 
    /**
@@ -323,8 +326,10 @@
             throw e;
          }
       }
+
       amqConnection.start() ;
       this._connection = amqConnection ;
+      _activated.set(true);
 
       _log.debug("Setup complete " + this);
    }
@@ -422,7 +427,6 @@
                                         " of type " +
                                         destinationType.getName());
             _destination = Util.lookup(ctx, destinationName, destinationType);
-            //_destination = (Destination)ctx.lookup(destinationName);
 
          }
          else
@@ -490,7 +494,14 @@
 
    public void onException(final JMSException jmse)
    {
-      handleFailure(jmse) ;
+       if(_activated.get())
+       {
+           handleFailure(jmse) ;
+       }
+       else
+       {
+           _log.warn("Received JMSException: " + jmse + " while endpoint was not activated.");
+       }
    }
 
    /**
diff --git a/qpid/java/lib/cobertura/README.txt b/qpid/java/lib/cobertura/README.txt
index 8e4cc09..080bb5f 100644
--- a/qpid/java/lib/cobertura/README.txt
+++ b/qpid/java/lib/cobertura/README.txt
@@ -1,10 +1,9 @@
-Download the cobertura binary from the following location:

+Download the cobertura binary from the following location and expand it into
+this directory.
 

 http://cobertura.sourceforge.net/download.html
 

-

-Unpack it into the cobertura (this) directory with tar --strip-path 1 -xf.
-This should leave you with cobertura.jar in qpid/java/lib/cobertura.

+Alternatively run "ant download-cobertura" to do this automatically.
+(to set a http proxy for ant use ANT_OPTS="-Dhttp.proxyHost=<host> -Dhttp.proxyPort=<port>")
 

 Run "ant cover-test coverage-report" to generate coverage report.
-
diff --git a/qpid/java/lib/poms/je-4.0.117.xml b/qpid/java/lib/poms/je-4.0.117.xml
deleted file mode 100644
index 85573a9..0000000
--- a/qpid/java/lib/poms/je-4.0.117.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0"?>
-<!--
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   The ASF licenses this file to You under the Apache License, Version 2.0
-   (the "License"); you may not use this file except in compliance with
-   the License.  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
--->
-<dep>
-  <groupId>com.sleepycat</groupId>
-  <artifactId>je</artifactId>
-  <version>4.0.117</version>
-</dep>
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java
index d2950b0..5c5ad66 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/prefetch/PrefetchBehaviourTest.java
@@ -5,12 +5,14 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.jms.Connection;
+import javax.jms.Destination;
 import javax.jms.Message;
 import javax.jms.MessageConsumer;
 import javax.jms.MessageListener;
 import javax.jms.MessageProducer;
 import javax.jms.Queue;
 import javax.jms.Session;
+import javax.jms.TextMessage;
 
 import org.apache.qpid.configuration.ClientProperties;
 import org.apache.qpid.test.utils.QpidBrokerTestCase;
@@ -133,4 +135,41 @@
         assertFalse("Unexpecte exception during async message processing",_exceptionCaught.get());
     }
 
+    /**
+     * Test Goal: Verify if connection stop releases all messages in it's prefetch buffer.
+     * Test Strategy: Send 10 messages to a queue. Create a consumer with maxprefetch of 5, but never consume them.
+     *                Stop the connection. Create a new connection and a consumer with maxprefetch 10 on the same queue.
+     *                Try to receive all 10 messages.
+     */
+    public void testConnectionStop() throws Exception
+    {
+        setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, "10");
+        Connection con = getConnection();
+        con.start();
+        Session ssn = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination queue = ssn.createQueue("ADDR:my-queue;{create: always}");
+
+        MessageProducer prod = ssn.createProducer(queue);
+        for (int i=0; i<10;i++)
+        {
+           prod.send(ssn.createTextMessage("Msg" + i));
+        }
+
+        MessageConsumer consumer = ssn.createConsumer(queue);
+        // This is to ensure we get the first client to prefetch.
+        Message msg = consumer.receive(1000);
+        assertNotNull("The first consumer should get one message",msg);
+        con.stop();
+
+        Connection con2 = getConnection();
+        con2.start();
+        Session ssn2 = con2.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageConsumer consumer2 = ssn2.createConsumer(queue);
+        for (int i=0; i<9;i++)
+        {
+           TextMessage m = (TextMessage)consumer2.receive(1000);
+           assertNotNull("The second consumer should get 9 messages, but received only " + i,m);
+        }
+    }
+
 }
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java
new file mode 100644
index 0000000..08a932e
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/MessageGroupQueueTest.java
@@ -0,0 +1,481 @@
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+package org.apache.qpid.server.queue;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.client.AMQConnection;
+import org.apache.qpid.client.AMQDestination;
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MessageGroupQueueTest extends QpidBrokerTestCase
+{
+    protected final String QUEUE = "MessageGroupQueue";
+
+    private Connection producerConnection;
+    private MessageProducer producer;
+    private Session producerSession;
+    private Queue queue;
+    private Connection consumerConnection;
+    
+    
+    protected void setUp() throws Exception
+    {
+        super.setUp();
+
+        producerConnection = getConnection();
+        producerSession = producerConnection.createSession(true, Session.AUTO_ACKNOWLEDGE);
+
+        producerConnection.start();
+
+        consumerConnection = getConnection();
+        
+    }
+
+    protected void tearDown() throws Exception
+    {
+        producerConnection.close();
+        consumerConnection.close();
+        super.tearDown();
+    }
+
+
+    public void testSimpleGroupAssignment() throws Exception
+    {
+        simpleGroupAssignment(false);
+    }
+
+    public void testSharedGroupSimpleGroupAssignment() throws Exception
+    {
+        simpleGroupAssignment(true);
+    }
+
+
+    /**
+     * Pre populate the queue with messages with groups as follows
+     *
+     *  ONE
+     *  TWO
+     *  ONE
+     *  TWO
+     *
+     *  Create two consumers with prefetch of 1, the first consumer should then be assigned group ONE, the second
+     *  consumer assigned group TWO if they are started in sequence.
+     *
+     *  Thus doing
+     *
+     *  c1 <--- (ONE)
+     *  c2 <--- (TWO)
+     *  c2 ack --->
+     *
+     *  c2 should now be able to receive a second message from group TWO (skipping over the message from group ONE)
+     *
+     *  i.e.
+     *
+     *  c2 <--- (TWO)
+     *  c2 ack --->
+     *  c1 <--- (ONE)
+     *  c1 ack --->
+     *
+     */
+    private void simpleGroupAssignment(boolean sharedGroups) throws AMQException, JMSException
+    {
+        final Map<String,Object> arguments = new HashMap<String, Object>();
+        arguments.put("qpid.group_header_key","group");
+        if(sharedGroups)
+        {
+            arguments.put("qpid.shared_msg_group","1");
+        }
+        ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+        queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
+
+        ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+        producer = producerSession.createProducer(queue);
+
+        String[] groups = { "ONE", "TWO"};
+
+        for (int msg = 0; msg < 4; msg++)
+        {
+            producer.send(createMessage(msg, groups[msg % groups.length]));
+        }
+        producerSession.commit();
+        producer.close();
+        producerSession.close();
+        producerConnection.close();
+
+        Session cs1 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1);
+        Session cs2 = ((AMQConnection)consumerConnection).createSession(false, Session.CLIENT_ACKNOWLEDGE,1);
+
+
+        MessageConsumer consumer1 = cs1.createConsumer(queue);
+        MessageConsumer consumer2 = cs2.createConsumer(queue);
+
+        consumerConnection.start();
+        Message cs1Received = consumer1.receive(1000);
+        assertNotNull("Consumer 1 should have received first message", cs1Received);
+
+        Message cs2Received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received first message", cs2Received);
+
+        cs1Received.acknowledge();
+        cs2Received.acknowledge();
+
+        Message cs2Received2 = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received second message", cs2Received2);
+        assertEquals("Differing groups", cs2Received2.getStringProperty("group"),
+                     cs2Received.getStringProperty("group"));
+
+        Message cs1Received2 = consumer1.receive(1000);
+
+        assertNotNull("Consumer 1 should have received second message", cs1Received2);
+        assertEquals("Differing groups", cs1Received2.getStringProperty("group"),
+                     cs1Received.getStringProperty("group"));
+
+        cs1Received2.acknowledge();
+        cs2Received2.acknowledge();
+
+        assertNull(consumer1.receive(1000));
+        assertNull(consumer2.receive(1000));
+    }
+
+
+    public void testConsumerCloseGroupAssignment() throws Exception
+    {
+        consumerCloseGroupAssignment(false);
+    }
+
+    public void testSharedGroupConsumerCloseGroupAssignment() throws Exception
+    {
+        consumerCloseGroupAssignment(true);
+    }
+
+    /**
+     *
+     * Tests that upon closing a consumer, groups previously assigned to that consumer are reassigned to a different
+     * consumer.
+     *
+     * Pre-populate the queue as ONE, ONE, TWO, ONE
+     *
+     * create in sequence two consumers
+     *
+     * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2)
+     *
+     * Then close c1 before acking.
+     *
+     * If we now attempt to receive from c2, then the remaining messages in group ONE should be available (which
+     * requires c2 to go "backwards" in the queue).
+     *
+     **/
+    private void consumerCloseGroupAssignment(boolean sharedGroups) throws AMQException, JMSException
+    {
+        final Map<String,Object> arguments = new HashMap<String, Object>();
+        arguments.put("qpid.group_header_key","group");
+        if(sharedGroups)
+        {
+            arguments.put("qpid.shared_msg_group","1");
+        }
+        ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+        queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
+
+        ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+        producer = producerSession.createProducer(queue);
+
+        producer.send(createMessage(1, "ONE"));
+        producer.send(createMessage(2, "ONE"));
+        producer.send(createMessage(3, "TWO"));
+        producer.send(createMessage(4, "ONE"));
+
+        producerSession.commit();
+        producer.close();
+        producerSession.close();
+        producerConnection.close();
+
+        Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1);
+        Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1);
+
+        MessageConsumer consumer1 = cs1.createConsumer(queue);
+
+        consumerConnection.start();
+        MessageConsumer consumer2 = cs2.createConsumer(queue);
+
+        Message cs1Received = consumer1.receive(1000);
+        assertNotNull("Consumer 1 should have received first message", cs1Received);
+        assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg"));
+
+        Message cs2Received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received first message", cs2Received);
+        assertEquals("incorrect message received", 3, cs2Received.getIntProperty("msg"));
+        cs2.commit();
+
+        Message cs2Received2 = consumer2.receive(1000);
+
+        assertNull("Consumer 2 should not yet have received a second message", cs2Received2);
+
+        consumer1.close();
+
+        cs1.commit();
+        Message cs2Received3 = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received second message", cs2Received3);
+        assertEquals("Unexpected group", "ONE", cs2Received3.getStringProperty("group"));
+        assertEquals("incorrect message received", 2, cs2Received3.getIntProperty("msg"));
+
+        cs2.commit();
+
+
+        Message cs2Received4 = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received third message", cs2Received4);
+        assertEquals("Unexpected group", "ONE", cs2Received4.getStringProperty("group"));
+        assertEquals("incorrect message received", 4, cs2Received4.getIntProperty("msg"));
+        cs2.commit();
+
+        assertNull(consumer2.receive(1000));
+    }
+
+
+
+    
+    public void testConsumerCloseWithRelease() throws Exception
+    {
+        consumerCloseWithRelease(false);
+    }
+
+    public void testSharedGroupConsumerCloseWithRelease() throws Exception
+    {
+        consumerCloseWithRelease(true);
+    }
+
+
+    /**
+     *
+     * Tests that upon closing a consumer and its session, groups previously assigned to that consumer are reassigned
+     * toa different consumer, including messages which were previously delivered but have now been released.
+     *
+     * Pre-populate the queue as ONE, ONE, TWO, ONE
+     *
+     * create in sequence two consumers
+     *
+     * receive first from c1 then c2 (thus ONE is assigned to c1, TWO to c2)
+     *
+     * Then close c1 and its session without acking.
+     *
+     * If we now attempt to receive from c2, then the all messages in group ONE should be available (which
+     * requires c2 to go "backwards" in the queue). The first such message should be marked as redelivered
+     *
+     */
+    private void consumerCloseWithRelease(boolean sharedGroups) throws AMQException, JMSException
+    {
+        final Map<String,Object> arguments = new HashMap<String, Object>();
+        arguments.put("qpid.group_header_key","group");
+        if(sharedGroups)
+        {
+            arguments.put("qpid.shared_msg_group","1");
+        }
+
+        ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+        queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
+
+        ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+        producer = producerSession.createProducer(queue);
+
+        producer.send(createMessage(1, "ONE"));
+        producer.send(createMessage(2, "ONE"));
+        producer.send(createMessage(3, "TWO"));
+        producer.send(createMessage(4, "ONE"));
+
+        producerSession.commit();
+        producer.close();
+        producerSession.close();
+        producerConnection.close();
+
+        Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1);
+        Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1);
+
+
+        MessageConsumer consumer1 = cs1.createConsumer(queue);
+
+        consumerConnection.start();
+
+        MessageConsumer consumer2 = cs2.createConsumer(queue);
+
+        Message cs1Received = consumer1.receive(1000);
+        assertNotNull("Consumer 1 should have received its first message", cs1Received);
+        assertEquals("incorrect message received", 1, cs1Received.getIntProperty("msg"));
+
+        Message received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received its first message", received);
+        assertEquals("incorrect message received", 3, received.getIntProperty("msg"));
+
+        received = consumer2.receive(1000);
+
+        assertNull("Consumer 2 should not yet have received second message", received);
+
+        consumer1.close();
+        cs1.close();
+        cs2.commit();
+        received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should now have received second message", received);
+        assertEquals("Unexpected group", "ONE", received.getStringProperty("group"));
+        assertEquals("incorrect message received", 1, received.getIntProperty("msg"));
+        assertTrue("Expected second message to be marked as redelivered " + received.getIntProperty("msg"),
+                   received.getJMSRedelivered());
+
+        cs2.commit();
+
+
+        received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received a third message", received);
+        assertEquals("Unexpected group", "ONE", received.getStringProperty("group"));
+        assertEquals("incorrect message received", 2, received.getIntProperty("msg"));
+
+        cs2.commit();
+
+        received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received a fourth message", received);
+        assertEquals("Unexpected group", "ONE", received.getStringProperty("group"));
+        assertEquals("incorrect message received", 4, received.getIntProperty("msg"));
+
+        cs2.commit();
+
+
+        assertNull(consumer2.receive(1000));
+    }
+
+    public void testGroupAssignmentSurvivesEmpty() throws JMSException, AMQException
+    {
+        groupAssignmentOnEmpty(false);
+    }
+
+    public void testSharedGroupAssignmentDoesNotSurviveEmpty() throws JMSException, AMQException
+    {
+        groupAssignmentOnEmpty(true);
+    }
+
+    private void groupAssignmentOnEmpty(boolean sharedGroups) throws AMQException, JMSException
+    {
+        final Map<String,Object> arguments = new HashMap<String, Object>();
+        arguments.put("qpid.group_header_key","group");
+        if(sharedGroups)
+        {
+            arguments.put("qpid.shared_msg_group","1");
+        }
+
+        ((AMQSession) producerSession).createQueue(new AMQShortString(QUEUE), true, false, false, arguments);
+        queue = (Queue) producerSession.createQueue("direct://amq.direct/"+QUEUE+"/"+QUEUE+"?durable='false'&autodelete='true'");
+
+        ((AMQSession) producerSession).declareAndBind((AMQDestination)queue);
+        producer = producerSession.createProducer(queue);
+
+        producer.send(createMessage(1, "ONE"));
+        producer.send(createMessage(2, "TWO"));
+        producer.send(createMessage(3, "THREE"));
+        producer.send(createMessage(4, "ONE"));
+
+        producerSession.commit();
+        producer.close();
+        producerSession.close();
+        producerConnection.close();
+
+        Session cs1 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1);
+        Session cs2 = ((AMQConnection)consumerConnection).createSession(true, Session.SESSION_TRANSACTED,1);
+
+
+        MessageConsumer consumer1 = cs1.createConsumer(queue);
+
+        consumerConnection.start();
+
+        MessageConsumer consumer2 = cs2.createConsumer(queue);
+
+        Message received = consumer1.receive(1000);
+        assertNotNull("Consumer 1 should have received its first message", received);
+        assertEquals("incorrect message received", 1, received.getIntProperty("msg"));
+
+        received = consumer2.receive(1000);
+
+        assertNotNull("Consumer 2 should have received its first message", received);
+        assertEquals("incorrect message received", 2, received.getIntProperty("msg"));
+
+        cs1.commit();
+
+        received = consumer1.receive(1000);
+        assertNotNull("Consumer 1 should have received its second message", received);
+        assertEquals("incorrect message received", 3, received.getIntProperty("msg"));
+
+        // We expect different behaviours from "shared groups": here the assignment of a subscription to a group
+        // is terminated when there are no outstanding delivered but unacknowledged messages.  In contrast, with a
+        // standard message grouping queue the assignment will be retained until the subscription is no longer
+        // registered
+        if(sharedGroups)
+        {
+            cs2.commit();
+            received = consumer2.receive(1000);
+
+            assertNotNull("Consumer 2 should have received its second message", received);
+            assertEquals("incorrect message received", 4, received.getIntProperty("msg"));
+
+            cs2.commit();
+        }
+        else
+        {
+            cs2.commit();
+            received = consumer2.receive(1000);
+
+            assertNull("Consumer 2 should not have received a second message", received);
+
+            cs1.commit();
+
+            received = consumer1.receive(1000);
+            assertNotNull("Consumer 1 should have received its third message", received);
+            assertEquals("incorrect message received", 4, received.getIntProperty("msg"));
+
+        }
+
+    }
+
+
+    private Message createMessage(int msg, String group) throws JMSException
+    {
+        Message send = producerSession.createTextMessage("Message: " + msg);
+        send.setIntProperty("msg", msg);
+        send.setStringProperty("group", group);
+
+        return send;
+    }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
index 775d2c3..47f334a 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/queue/ProducerFlowControlTest.java
@@ -154,8 +154,7 @@
         // try to send 5 messages (should block after 4)
         sendMessagesAsync(producer, producerSession, 5, 50L);
 
-        Thread.sleep(5000);
-        List<String> results = waitAndFindMatches("QUE-1003");
+        List<String> results = waitAndFindMatches("QUE-1003", 7000);
 
         assertEquals("Did not find correct number of QUE-1003 queue overfull messages", 1, results.size());
 
@@ -199,11 +198,13 @@
         // try to send 5 messages (should block after 4)
         MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L);
 
-        Thread.sleep(TIMEOUT);
         List<String> results = waitAndFindMatches("Message send delayed by", TIMEOUT);
         assertTrue("No delay messages logged by client",results.size()!=0);
-        results = findMatches("Message send failed due to timeout waiting on broker enforced flow control");
-        assertEquals("Incorrect number of send failure messages logged by client",1,results.size());
+
+        List<String> failedMessages = waitAndFindMatches("Message send failed due to timeout waiting on broker enforced"
+                                                  + " flow control", TIMEOUT);
+        assertEquals("Incorrect number of send failure messages logged by client (got " + results.size() + " delay "
+                     + "messages)",1,failedMessages.size());
 
 
 
@@ -325,8 +326,9 @@
 
 
         // try to send 5 messages (should block after 4)
-        MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 50L);
+        MessageSender sender = sendMessagesAsync(producer, producerSession, 5, 100L);
 
+        
         Thread.sleep(10000);
 
         Exception e = sender.getException();
@@ -440,6 +442,15 @@
                 e.printStackTrace();
                 throw new RuntimeException(e);
             }
+
+            try
+            {
+                Thread.sleep(sleepPeriod);
+            }
+            catch (InterruptedException e)
+            {
+                throw new RuntimeException(e);
+            }
         }
     }
 
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java
index a5c38e7..2d450cf 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/store/SlowMessageStore.java
@@ -22,11 +22,13 @@
 
 import org.apache.commons.configuration.Configuration;
 import org.apache.log4j.Logger;
-import org.apache.qpid.AMQException;
 import org.apache.qpid.AMQStoreException;
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.server.exchange.Exchange;
+import org.apache.qpid.server.federation.Bridge;
+import org.apache.qpid.server.federation.BrokerLink;
+import org.apache.qpid.server.message.EnqueableMessage;
 import org.apache.qpid.server.queue.AMQQueue;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.logging.LogSubject;
@@ -35,7 +37,7 @@
 import java.util.Iterator;
 import java.nio.ByteBuffer;
 
-public class SlowMessageStore implements MessageStore
+public class SlowMessageStore implements MessageStore, DurableConfigurationStore
 {
     private static final Logger _logger = Logger.getLogger(SlowMessageStore.class);
     private static final String DELAYS = "delays";
@@ -43,6 +45,7 @@
     private HashMap<String, Long> _postDelays = new HashMap<String, Long>();
     private long _defaultDelay = 0L;
     private MessageStore _realStore = new MemoryMessageStore();
+    private DurableConfigurationStore _durableConfigurationStore = (MemoryMessageStore) _realStore;
     private static final String PRE = "pre";
     private static final String POST = "post";
     private String DEFAULT_DELAY = "default";
@@ -80,12 +83,13 @@
                                              " does not.");
             }
             _realStore = (MessageStore) o;
-            _realStore.configureConfigStore(name, recoveryHandler, config, logSubject);
+            if(o instanceof DurableConfigurationStore)
+            {
+                _durableConfigurationStore = (DurableConfigurationStore)o;
+            }
         }
-        else
-        {
-            _realStore.configureConfigStore(name, recoveryHandler, config, logSubject);
-        }
+        _durableConfigurationStore.configureConfigStore(name, recoveryHandler, config, logSubject);
+
     }
 
     private void configureDelays(Configuration config)
@@ -178,28 +182,28 @@
     public void createExchange(Exchange exchange) throws AMQStoreException
     {
         doPreDelay("createExchange");
-        _realStore.createExchange(exchange);
+        _durableConfigurationStore.createExchange(exchange);
         doPostDelay("createExchange");
     }
 
     public void removeExchange(Exchange exchange) throws AMQStoreException
     {
         doPreDelay("removeExchange");
-        _realStore.removeExchange(exchange);
+        _durableConfigurationStore.removeExchange(exchange);
         doPostDelay("removeExchange");
     }
 
     public void bindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException
     {
         doPreDelay("bindQueue");
-        _realStore.bindQueue(exchange, routingKey, queue, args);
+        _durableConfigurationStore.bindQueue(exchange, routingKey, queue, args);
         doPostDelay("bindQueue");
     }
 
     public void unbindQueue(Exchange exchange, AMQShortString routingKey, AMQQueue queue, FieldTable args) throws AMQStoreException
     {
         doPreDelay("unbindQueue");
-        _realStore.unbindQueue(exchange, routingKey, queue, args);
+        _durableConfigurationStore.unbindQueue(exchange, routingKey, queue, args);
         doPostDelay("unbindQueue");
     }
 
@@ -211,14 +215,14 @@
     public void createQueue(AMQQueue queue, FieldTable arguments) throws AMQStoreException
     {
         doPreDelay("createQueue");
-        _realStore.createQueue(queue, arguments);
+        _durableConfigurationStore.createQueue(queue, arguments);
         doPostDelay("createQueue");
     }
 
     public void removeQueue(AMQQueue queue) throws AMQStoreException
     {
         doPreDelay("removeQueue");
-        _realStore.removeQueue(queue);
+        _durableConfigurationStore.removeQueue(queue);
         doPostDelay("removeQueue");
     }
 
@@ -268,19 +272,19 @@
             _underlying = underlying;
         }
 
-        public void enqueueMessage(TransactionLogResource queue, Long messageId)
+        public void enqueueMessage(TransactionLogResource queue, EnqueableMessage message)
                 throws AMQStoreException
         {
             doPreDelay("enqueueMessage");
-            _underlying.enqueueMessage(queue, messageId);
+            _underlying.enqueueMessage(queue, message);
             doPostDelay("enqueueMessage");
         }
 
-        public void dequeueMessage(TransactionLogResource queue, Long messageId)
+        public void dequeueMessage(TransactionLogResource queue, EnqueableMessage message)
                 throws AMQStoreException
         {
             doPreDelay("dequeueMessage");
-            _underlying.dequeueMessage(queue, messageId);
+            _underlying.dequeueMessage(queue, message);
             doPostDelay("dequeueMessage");
         }
 
@@ -313,9 +317,36 @@
     public void updateQueue(AMQQueue queue) throws AMQStoreException
     {
         doPreDelay("updateQueue");
-        _realStore.updateQueue(queue);
+        _durableConfigurationStore.updateQueue(queue);
         doPostDelay("updateQueue");
     }
 
 
+    public void createBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+        doPreDelay("createBrokerLink");
+        _durableConfigurationStore.createBrokerLink(link);
+        doPostDelay("createBrokerLink");
+    }
+
+    public void deleteBrokerLink(final BrokerLink link) throws AMQStoreException
+    {
+        doPreDelay("deleteBrokerLink");
+        _durableConfigurationStore.deleteBrokerLink(link);
+        doPostDelay("deleteBrokerLink");
+    }
+
+    public void createBridge(final Bridge bridge) throws AMQStoreException
+    {
+        doPreDelay("createBridge");
+        _durableConfigurationStore.createBridge(bridge);
+        doPostDelay("createBridge");
+    }
+
+    public void deleteBridge(final Bridge bridge) throws AMQStoreException
+    {
+        doPreDelay("deleteBridge");
+        _durableConfigurationStore.deleteBridge(bridge);
+        doPostDelay("deleteBridge");
+    }
 }
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java
index 147a03b..fa16152 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/message/ObjectMessageTest.java
@@ -138,4 +138,21 @@
         
         assertEquals("Second read: UUIDs were not equal", sent, result);
     }
+
+
+    public void testSendEmptyObjectMessage() throws JMSException
+    {
+        ObjectMessage testMessage = _session.createObjectMessage();
+        testMessage.setStringProperty("test-property", "test-value");
+        assertNotNull("Object was null", testMessage.toString());
+
+        _producer.send(testMessage);
+
+        ObjectMessage receivedMessage = (ObjectMessage) _consumer.receive(1000);
+
+        assertNotNull("Message was not received.", receivedMessage);
+        assertNull("No object was sent", receivedMessage.getObject());
+        assertEquals("Unexpected property received", "test-value", receivedMessage.getStringProperty("test-property"));
+    }
+
 }
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java
index e3557ef..e7c3fad 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/client/queue/QueuePolicyTest.java
@@ -53,6 +53,10 @@
         super.tearDown();
     }
     
+    /**
+     * Test Goal : To create a ring queue programitcally with max queue count using the
+     *             address string and observe that it works as expected.
+     */
     public void testRejectPolicy() throws Exception
     {
         String addr = "ADDR:queue; {create: always, " +
@@ -82,6 +86,10 @@
         }
     }
     
+    /**
+     * Test Goal : To create a ring queue programitcally using the address string and observe
+     *             that it works as expected.
+     */
     public void testRingPolicy() throws Exception
     {
         Session ssn = _connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
@@ -94,17 +102,18 @@
         MessageConsumer consumer = ssn.createConsumer(dest);
         MessageProducer prod = ssn.createProducer(ssn.createQueue("ADDR:amq.direct/test"));
         
+        _connection.stop();
+
         prod.send(ssn.createTextMessage("Test1"));
         prod.send(ssn.createTextMessage("Test2"));
         prod.send(ssn.createTextMessage("Test3"));
+
+        _connection.start();
         
         TextMessage msg = (TextMessage)consumer.receive(1000);
-        assertEquals("The consumer should receive the msg with body='Test2'",msg.getText(),"Test2");
+        assertEquals("The consumer should receive the msg with body='Test2'","Test2",msg.getText());
         
         msg = (TextMessage)consumer.receive(1000);
-        assertEquals("The consumer should receive the msg with body='Test3'",msg.getText(),"Test3");
-     
-        prod.send(ssn.createTextMessage("Test4"));
-        assertEquals("The consumer should receive the msg with body='Test4'",msg.getText(),"Test3");
+        assertEquals("The consumer should receive the msg with body='Test3'","Test3",msg.getText());
     }
 }
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
index 7f166d0..20044b7 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/client/connection/ConnectionCloseTest.java
@@ -20,19 +20,11 @@
  */
 package org.apache.qpid.test.unit.client.connection;
 
-import org.apache.qpid.test.utils.QpidBrokerTestCase;
-import org.apache.qpid.transport.util.Logger;
-
-import java.util.HashMap;
-import java.util.Map;
-
 import javax.jms.Connection;
 import javax.jms.JMSException;
-import javax.jms.MessageConsumer;
-import javax.jms.MessageProducer;
-import javax.jms.Queue;
 import javax.jms.Session;
-import javax.jms.TextMessage;
+
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
 
 /**
  * ConnectionCloseTest
@@ -42,63 +34,6 @@
 public class ConnectionCloseTest extends QpidBrokerTestCase
 {
 
-    private static final Logger log = Logger.get(ConnectionCloseTest.class);
-
-    public void testSendReceiveClose() throws Exception
-    {
-        Map<Thread,StackTraceElement[]> before = Thread.getAllStackTraces();
-
-        for (int i = 0; i < 50; i++)
-        {
-            if ((i % 10) == 0)
-            {
-                log.warn("%d messages sent and received", i);
-            }
-
-            Connection receiver = getConnection();
-            receiver.start();
-            Session rssn = receiver.createSession(false, Session.AUTO_ACKNOWLEDGE);
-            Queue queue = rssn.createQueue("connection-close-test-queue");
-            MessageConsumer cons = rssn.createConsumer(queue);
-
-            Connection sender = getConnection();
-            sender.start();
-            Session sssn = sender.createSession(false, Session.AUTO_ACKNOWLEDGE);
-            MessageProducer prod = sssn.createProducer(queue);
-            prod.send(sssn.createTextMessage("test"));
-            sender.close();
-
-            TextMessage m = (TextMessage) cons.receive(2000);
-            assertNotNull("message was lost", m);
-            assertEquals(m.getText(), "test");
-            receiver.close();
-        }
-
-        // The finalizer is notifying connector thread waiting on a selector key.
-        // This should leave the finalizer enough time to notify those threads 
-        synchronized (this)
-        {
-            this.wait(10000);
-        }
-
-        Map<Thread,StackTraceElement[]> after = Thread.getAllStackTraces();
-        
-        Map<Thread,StackTraceElement[]> delta = new HashMap<Thread,StackTraceElement[]>(after);
-        for (Thread t : before.keySet())
-        {
-            delta.remove(t);
-        }
-
-        dumpStacks(delta);
-
-        int deltaThreshold = (isExternalBroker()? 1 : 2) //InVM creates more thread pools in the same VM
-                            * (Runtime.getRuntime().availableProcessors() + 1) + 5; 
-
-        assertTrue("Spurious thread creation exceeded threshold, " +
-                   delta.size() + " threads created.",
-                   delta.size() < deltaThreshold);
-    }
-
     /**
      * This test is added due to QPID-3453 to test connection closing when AMQ
      * session is not closed but underlying transport session is in detached
@@ -124,14 +59,4 @@
         }
     }
 
-    private void dumpStacks(Map<Thread,StackTraceElement[]> map)
-    {
-        for (Map.Entry<Thread,StackTraceElement[]> entry : map.entrySet())
-        {
-            Throwable t = new Throwable();
-            t.setStackTrace(entry.getValue());
-            log.warn(t, entry.getKey().toString());
-        }
-    }
-
 }
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
index 653ab8f..3c0f951 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/unit/transacted/TransactedTest.java
@@ -31,6 +31,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import javax.jms.Connection;
+import javax.jms.IllegalStateException;
 import javax.jms.JMSException;
 import javax.jms.Message;
 import javax.jms.MessageConsumer;
@@ -303,6 +305,70 @@
         con2.close();
     }
 
+    public void testCommitOnClosedConnection() throws Exception
+    {
+        Connection connnection = getConnection();
+        javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED);
+        connnection.close();
+        try
+        {
+            transactedSession.commit();
+            fail("Commit on closed connection should throw IllegalStateException!");
+        }
+        catch(IllegalStateException e)
+        {
+            // passed
+        }
+    }
+
+    public void testCommitOnClosedSession() throws Exception
+    {
+        Connection connnection = getConnection();
+        javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED);
+        transactedSession.close();
+        try
+        {
+            transactedSession.commit();
+            fail("Commit on closed session should throw IllegalStateException!");
+        }
+        catch(IllegalStateException e)
+        {
+            // passed
+        }
+    }
+
+    public void testRollbackOnClosedSession() throws Exception
+    {
+        Connection connnection = getConnection();
+        javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED);
+        transactedSession.close();
+        try
+        {
+            transactedSession.rollback();
+            fail("Rollback on closed session should throw IllegalStateException!");
+        }
+        catch(IllegalStateException e)
+        {
+            // passed
+        }
+    }
+
+    public void testGetTransactedOnClosedSession() throws Exception
+    {
+        Connection connnection = getConnection();
+        javax.jms.Session transactedSession = connnection.createSession(true, Session.SESSION_TRANSACTED);
+        transactedSession.close();
+        try
+        {
+            transactedSession.getTransacted();
+            fail("According to Sun TCK invocation of Session#getTransacted on closed session should throw IllegalStateException!");
+        }
+        catch(IllegalStateException e)
+        {
+            // passed
+        }
+    }
+
     private void expect(String text, Message msg) throws JMSException
     {
         expect(text, msg, false);
diff --git a/qpid/java/test-profiles/CPPExcludes b/qpid/java/test-profiles/CPPExcludes
index 66a20bc..d8c463b 100755
--- a/qpid/java/test-profiles/CPPExcludes
+++ b/qpid/java/test-profiles/CPPExcludes
@@ -172,3 +172,9 @@
 // QPID-3133: On 0-10, the exception listener is currently not invoked when reconnection fails to occurs.
 org.apache.qpid.server.failover.FailoverMethodTest#*
 
+// CPP Broker does not implement non-"shared group" message groups
+org.apache.qpid.server.queue.MessageGroupQueueTest#testSimpleGroupAssignment
+org.apache.qpid.server.queue.MessageGroupQueueTest#testConsumerCloseGroupAssignment
+org.apache.qpid.server.queue.MessageGroupQueueTest#testConsumerCloseWithRelease
+org.apache.qpid.server.queue.MessageGroupQueueTest#testGroupAssignmentSurvivesEmpty
+
diff --git a/qpid/java/test-profiles/Java010Excludes b/qpid/java/test-profiles/Java010Excludes
index 59cb506..0de4c6b 100755
--- a/qpid/java/test-profiles/Java010Excludes
+++ b/qpid/java/test-profiles/Java010Excludes
@@ -45,9 +45,6 @@
 // 0-10 is not supported by the MethodRegistry
 org.apache.qpid.test.unit.close.JavaServerCloseRaceConditionTest#*
 
-//QPID-942 : Implemented Channel.Flow based Producer Side flow control to the Java Broker (not in CPP Broker)
-org.apache.qpid.server.queue.ProducerFlowControlTest#*
-
 //QPID-1864: rollback with subscriptions does not work in 0-10 yet
 org.apache.qpid.test.client.RollbackOrderTest#testOrderingAfterRollbackOnMessage