merge up to r1765852 from trunk
diff --git a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBCacheSizeSetter.java b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBCacheSizeSetter.java
index 394d498..3c25474 100644
--- a/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBCacheSizeSetter.java
+++ b/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/BDBCacheSizeSetter.java
@@ -28,14 +28,14 @@
 
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.ConfiguredObject;
-import org.apache.qpid.server.model.NoopConfigurationChangeListener;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.model.VirtualHostNode;
 import org.apache.qpid.server.util.ServerScopedRuntimeException;
 import org.apache.qpid.server.virtualhost.berkeleydb.BDBVirtualHost;
 
-public class BDBCacheSizeSetter extends NoopConfigurationChangeListener
+public class BDBCacheSizeSetter extends AbstractConfigurationChangeListener
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(BDBCacheSizeSetter.class);
 
diff --git a/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java b/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java
index 957fee6..ed0d367 100644
--- a/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java
+++ b/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAReplicaVirtualHostImpl.java
@@ -45,6 +45,7 @@
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
 import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.RemoteHostAddress;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.VirtualHostNode;
 import org.apache.qpid.server.model.port.AmqpPort;
@@ -53,8 +54,10 @@
 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.transfer.TransferQueue;
 import org.apache.qpid.server.transport.AMQPConnection;
 import org.apache.qpid.server.txn.DtxRegistry;
+import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.virtualhost.HouseKeepingTask;
 import org.apache.qpid.server.virtualhost.NodeAutoCreationPolicy;
 import org.apache.qpid.server.virtualhost.VirtualHostPrincipal;
@@ -511,6 +514,12 @@
     }
 
     @Override
+    public TransferQueue getTransferQueue()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public Principal getPrincipal()
     {
         return _principal;
@@ -541,6 +550,13 @@
     }
 
     @Override
+    public boolean makeConnection(final RemoteHostAddress<?> address, final Action<Boolean> onConnectionLoss)
+    {
+        throwUnsupportedForReplica();
+        return false;
+    }
+
+    @Override
     public UserPreferences createUserPreferences(final ConfiguredObject<?> object)
     {
         throwUnsupportedForReplica();
diff --git a/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java b/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java
index be5ef9a..48b14e0 100644
--- a/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java
+++ b/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java
@@ -45,6 +45,7 @@
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.RemoteReplicationNode;
@@ -269,7 +270,7 @@
 
         final AtomicReference<RemoteReplicationNode<?>> lastSeenReplica = new AtomicReference<>();
         final CountDownLatch remoteNodeLatch = new CountDownLatch(2);
-        node1.addChangeListener(new NoopConfigurationChangeListener()
+        node1.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void childAdded(ConfiguredObject<?> object, ConfiguredObject<?> child)
@@ -557,7 +558,7 @@
         Map<String, Object> node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber);
         BDBHAVirtualHostNode<?> node = _helper.createAndStartHaVHN(node1Attributes);
         final CountDownLatch stopLatch = new CountDownLatch(1);
-        ConfigurationChangeListener listener = new NoopConfigurationChangeListener()
+        ConfigurationChangeListener listener = new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(ConfiguredObject<?> object, State oldState, State newState)
@@ -578,7 +579,7 @@
 
         final CountDownLatch stateChangeLatch = new CountDownLatch(1);
         final CountDownLatch roleChangeLatch = new CountDownLatch(1);
-        node.addChangeListener(new NoopConfigurationChangeListener()
+        node.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
@@ -637,7 +638,7 @@
         BDBHAVirtualHostNode<?> node = _helper.createAndStartHaVHN(nodeAttributes);
 
         final CountDownLatch stopLatch = new CountDownLatch(1);
-        ConfigurationChangeListener listener = new NoopConfigurationChangeListener()
+        ConfigurationChangeListener listener = new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(ConfiguredObject<?> object, State oldState, State newState)
@@ -666,7 +667,7 @@
 
         final CountDownLatch stateChangeLatch = new CountDownLatch(1);
         final CountDownLatch roleChangeLatch = new CountDownLatch(1);
-        node.addChangeListener(new NoopConfigurationChangeListener()
+        node.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
@@ -719,7 +720,7 @@
 
         final AtomicInteger permittedNodesChangeCounter = new AtomicInteger();
         final CountDownLatch _permittedNodesLatch = new CountDownLatch(1);
-        node2.addChangeListener(new NoopConfigurationChangeListener()
+        node2.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void attributeSet(ConfiguredObject<?> object, String attributeName, Object oldAttributeValue, Object newAttributeValue)
@@ -776,7 +777,7 @@
         BDBHAVirtualHostNode<?> node1 = _helper.createAndStartHaVHN(node1Attributes);
 
         final CountDownLatch stopLatch = new CountDownLatch(1);
-        ConfigurationChangeListener listener = new NoopConfigurationChangeListener()
+        ConfigurationChangeListener listener = new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(ConfiguredObject<?> object, State oldState, State newState)
diff --git a/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/NoopConfigurationChangeListener.java b/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/NoopConfigurationChangeListener.java
deleted file mode 100644
index d157204..0000000
--- a/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/NoopConfigurationChangeListener.java
+++ /dev/null
@@ -1,65 +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.server.store.berkeleydb;
-
-import org.apache.qpid.server.model.ConfigurationChangeListener;
-import org.apache.qpid.server.model.ConfiguredObject;
-import org.apache.qpid.server.model.State;
-
-public class NoopConfigurationChangeListener implements ConfigurationChangeListener
-{
-
-    public NoopConfigurationChangeListener() {
-    }
-
-    @Override
-    public void stateChanged(ConfiguredObject<?> object, State oldState, State newState)
-    {
-    }
-
-    @Override
-    public void childAdded(ConfiguredObject<?> object, ConfiguredObject<?> child)
-    {
-    }
-
-    @Override
-    public void childRemoved(ConfiguredObject<?> object, ConfiguredObject<?> child)
-    {
-    }
-
-    @Override
-    public void attributeSet(ConfiguredObject<?> object, String attributeName, Object oldAttributeValue,
-                             Object newAttributeValue)
-    {
-    }
-
-    @Override
-    public void bulkChangeStart(final ConfiguredObject<?> object)
-    {
-
-    }
-
-    @Override
-    public void bulkChangeEnd(final ConfiguredObject<?> object)
-    {
-
-    }
-}
diff --git a/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java b/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java
index 2d94df1..207b720 100644
--- a/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java
+++ b/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java
@@ -20,7 +20,11 @@
  */
 package org.apache.qpid.server.virtualhostnode.berkeleydb;
 
-import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.util.Collections;
 import java.util.EnumSet;
@@ -28,17 +32,18 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import org.hamcrest.Description;
+import org.mockito.ArgumentMatcher;
+
 import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.LogMessage;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.messages.HighAvailabilityMessages;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.SystemConfig;
-import org.apache.qpid.server.store.berkeleydb.NoopConfigurationChangeListener;
 import org.apache.qpid.test.utils.PortHelper;
 import org.apache.qpid.test.utils.QpidTestCase;
-import org.hamcrest.Description;
-import org.mockito.ArgumentMatcher;
 
 /**
  * Class to test that specific VHN operations result in the expected Operational Log message(s) being performed.
@@ -264,7 +269,7 @@
         BDBHAVirtualHostNodeImpl node1 = (BDBHAVirtualHostNodeImpl)_helper.createHaVHN(node1Attributes);
 
         final CountDownLatch remoteNodeAdded = new CountDownLatch(1);
-        node1.addChangeListener(new NoopConfigurationChangeListener()
+        node1.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void childAdded(ConfiguredObject<?> object, ConfiguredObject<?> child)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/consumer/AbstractConsumerTarget.java b/broker-core/src/main/java/org/apache/qpid/server/consumer/AbstractConsumerTarget.java
index b936b52..b21f948 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/consumer/AbstractConsumerTarget.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/consumer/AbstractConsumerTarget.java
@@ -38,6 +38,7 @@
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.messages.SubscriptionMessages;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.model.Consumer;
 import org.apache.qpid.server.queue.SuspendedConsumerLoggingTicker;
 import org.apache.qpid.server.transport.AMQPConnection;
@@ -57,10 +58,10 @@
     private final boolean _isMultiQueue;
     private final SuspendedConsumerLoggingTicker _suspendedConsumerLoggingTicker;
     private ConcurrentLinkedQueue<ConsumerMessageInstancePair> _queue = new ConcurrentLinkedQueue();
-    private final List<ConsumerImpl> _consumers = new CopyOnWriteArrayList<>();
+    private final List<MessageInstanceConsumer> _consumers = new CopyOnWriteArrayList<>();
 
     private final boolean _isPullOnly;
-    private Iterator<ConsumerImpl> _pullIterator;
+    private Iterator<MessageInstanceConsumer> _pullIterator;
 
 
     protected AbstractConsumerTarget(final State initialState,
@@ -123,13 +124,13 @@
     protected abstract void processClosed();
 
     @Override
-    public void consumerAdded(final ConsumerImpl sub)
+    public void consumerAdded(final MessageInstanceConsumer sub)
     {
         _consumers.add(sub);
     }
 
     @Override
-    public void consumerRemoved(final ConsumerImpl sub)
+    public void consumerRemoved(final MessageInstanceConsumer sub)
     {
         _consumers.remove(sub);
         if(_consumers.isEmpty())
@@ -138,7 +139,7 @@
         }
     }
 
-    public List<ConsumerImpl> getConsumers()
+    public List<MessageInstanceConsumer> getConsumers()
     {
         return _consumers;
     }
@@ -246,6 +247,11 @@
         _stateChangeListeners.remove(listener);
     }
 
+    public boolean isPullOnly()
+    {
+        return _isPullOnly;
+    }
+
     public final boolean trySendLock()
     {
         return _stateChangeLock.tryLock();
@@ -262,13 +268,7 @@
     }
 
     @Override
-    public boolean isPullOnly()
-    {
-        return _isPullOnly;
-    }
-
-    @Override
-    public final long send(final ConsumerImpl consumer, MessageInstance entry, boolean batch)
+    public final long send(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
     {
         AMQPConnection<?> amqpConnection = getSessionModel().getAMQPConnection();
         amqpConnection.reserveOutboundMessageSpace(entry.getMessage().getSize());
@@ -277,7 +277,7 @@
         return entry.getMessage().getSize();
     }
 
-    protected abstract void doSend(final ConsumerImpl consumer, MessageInstance entry, boolean batch);
+    protected abstract void doSend(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch);
 
     @Override
     public boolean hasMessagesToSend()
@@ -289,7 +289,7 @@
     {
         if(hasCredit())
         {
-            for (ConsumerImpl consumer : _consumers)
+            for (MessageInstanceConsumer consumer : _consumers)
             {
                 if (consumer.hasAvailableMessages())
                 {
@@ -311,7 +311,7 @@
             }
             if(_pullIterator.hasNext())
             {
-                ConsumerImpl consumer = _pullIterator.next();
+                MessageInstanceConsumer consumer = _pullIterator.next();
                 consumer.pullMessage();
             }
         }
@@ -321,7 +321,7 @@
             try
             {
 
-                ConsumerImpl consumer = consumerMessage.getConsumer();
+                MessageInstanceConsumer consumer = consumerMessage.getConsumer();
                 MessageInstance entry = consumerMessage.getEntry();
                 boolean batch = consumerMessage.isBatch();
                 doSend(consumer, entry, batch);
@@ -375,7 +375,7 @@
             releaseSendLock();
         }
 
-        for (ConsumerImpl consumer : _consumers)
+        for (MessageInstanceConsumer consumer : _consumers)
         {
             consumer.close();
         }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerImpl.java b/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerImpl.java
deleted file mode 100644
index cf91f75..0000000
--- a/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerImpl.java
+++ /dev/null
@@ -1,86 +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.server.consumer;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.apache.qpid.server.message.MessageSource;
-import org.apache.qpid.server.protocol.AMQSessionModel;
-
-public interface ConsumerImpl
-{
-    AtomicLong CONSUMER_NUMBER_GENERATOR = new AtomicLong(0);
-
-    void externalStateChange();
-
-    ConsumerTarget getTarget();
-
-    boolean hasAvailableMessages();
-
-    void pullMessage();
-
-    enum Option
-    {
-        ACQUIRES,
-        SEES_REQUEUES,
-        TRANSIENT,
-        EXCLUSIVE,
-        NO_LOCAL,
-        DURABLE
-    }
-
-    long getBytesOut();
-
-    long getMessagesOut();
-
-    long getUnacknowledgedBytes();
-
-    long getUnacknowledgedMessages();
-
-    AMQSessionModel getSessionModel();
-
-    MessageSource getMessageSource();
-
-    long getConsumerNumber();
-
-    boolean isSuspended();
-
-    boolean isClosed();
-
-    boolean acquires();
-
-    boolean seesRequeues();
-
-    void close();
-
-    boolean trySendLock();
-
-
-    void getSendLock();
-
-    void releaseSendLock();
-
-    boolean isActive();
-
-    String getName();
-
-    void flush();
-}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerMessageInstancePair.java b/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerMessageInstancePair.java
index 9b5f9c9..ad85529 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerMessageInstancePair.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerMessageInstancePair.java
@@ -20,16 +20,17 @@
 package org.apache.qpid.server.consumer;
 
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageReference;
 
 public class ConsumerMessageInstancePair
 {
-    private final ConsumerImpl _consumer;
+    private final MessageInstanceConsumer _consumer;
     private final MessageInstance _entry;
     private final boolean _batch;
     private final MessageReference _reference;
 
-    public ConsumerMessageInstancePair(final ConsumerImpl consumer, final MessageInstance entry, final boolean batch)
+    public ConsumerMessageInstancePair(final MessageInstanceConsumer consumer, final MessageInstance entry, final boolean batch)
     {
         _consumer = consumer;
         _entry = entry;
@@ -38,7 +39,7 @@
 
     }
 
-    public ConsumerImpl getConsumer()
+    public MessageInstanceConsumer getConsumer()
     {
         return _consumer;
     }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java b/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java
index 7b9ac65..9d76a39 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/consumer/ConsumerTarget.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.server.consumer;
 
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.protocol.AMQSessionModel;
 import org.apache.qpid.server.util.StateChangeListener;
@@ -50,9 +51,9 @@
 
     State getState();
 
-    void consumerAdded(ConsumerImpl sub);
+    void consumerAdded(MessageInstanceConsumer consumer);
 
-    void consumerRemoved(ConsumerImpl sub);
+    void consumerRemoved(MessageInstanceConsumer consumer);
 
     void notifyCurrentState();
 
@@ -64,7 +65,7 @@
 
     AMQSessionModel getSessionModel();
 
-    long send(final ConsumerImpl consumer, MessageInstance entry, boolean batch);
+    long send(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch);
 
     boolean hasMessagesToSend();
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
index 879ea17..8169b94 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java
@@ -50,8 +50,8 @@
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.messages.ExchangeMessages;
 import org.apache.qpid.server.logging.subjects.ExchangeLogSubject;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
-import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.AbstractConfiguredObject;
@@ -446,7 +446,7 @@
                                                                                         final String routingAddress,
                                                                                         final InstanceProperties instanceProperties,
                                                                                         final ServerTransaction txn,
-                                                                                        final Action<? super MessageInstance> postEnqueueAction)
+                                                                                        final Action<? super BaseMessageInstance> postEnqueueAction)
     {
         if (_virtualHost.getState() != State.ACTIVE)
         {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java b/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java
index 9e8ba67..71e1ec9 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/exchange/DefaultDestination.java
@@ -22,9 +22,9 @@
 import java.util.Map;
 
 import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
-import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Exchange;
@@ -96,13 +96,13 @@
                                                                                         String routingAddress,
                                                                                         final InstanceProperties instanceProperties,
                                                                                         final ServerTransaction txn,
-                                                                                        final Action<? super MessageInstance> postEnqueueAction)
+                                                                                        final Action<? super BaseMessageInstance> postEnqueueAction)
     {
         if(routingAddress == null || routingAddress.trim().equals(""))
         {
             return 0;
         }
-        final MessageDestination dest = _virtualHost.getAttainedMessageDestination(routingAddress);
+        MessageDestination dest = _virtualHost.getAttainedMessageDestination(routingAddress);
         if(dest == null)
         {
             routingAddress = _virtualHost.getLocalAddress(routingAddress);
@@ -117,10 +117,10 @@
             }
             else if(!routingAddress.contains("/"))
             {
-                Exchange<?> exchange = _virtualHost.getAttainedChildFromAddress(Exchange.class, routingAddress);
-                if(exchange != null)
+                dest = _virtualHost.getAttainedMessageDestination(routingAddress);
+                if(dest != null)
                 {
-                    return exchange.send(message, "", instanceProperties, txn, postEnqueueAction);
+                    return dest.send(message, dest instanceof Exchange ? "" : routingAddress, instanceProperties, txn, postEnqueueAction);
                 }
             }
             return 0;
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/federation/OutboundProtocolEngine.java
similarity index 67%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/federation/OutboundProtocolEngine.java
index d2aff53..0397040 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/OutboundProtocolEngine.java
@@ -18,8 +18,15 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.federation;
 
-public interface QueueEntryListBase extends QueueEntryList
+import org.apache.qpid.server.transport.ProtocolEngine;
+import org.apache.qpid.server.transport.SchedulableConnection;
+import org.apache.qpid.server.util.Action;
+
+public interface OutboundProtocolEngine extends ProtocolEngine
 {
+    void setConnection(SchedulableConnection connection);
+
+    void setOnClosedTask(Action<Boolean> onConnectionLoss);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/federation/RemoteHostAddressImpl.java b/broker-core/src/main/java/org/apache/qpid/server/federation/RemoteHostAddressImpl.java
new file mode 100644
index 0000000..a437d73
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/RemoteHostAddressImpl.java
@@ -0,0 +1,179 @@
+/*
+ *
+ * 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.federation;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.apache.qpid.configuration.CommonProperties;
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.RemoteHost;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.StateTransition;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.util.ParameterizedTypes;
+
+@ManagedObject( category = false, type = RemoteHostAddress.REMOTE_HOST_ADDRESS_TYPE )
+class RemoteHostAddressImpl extends AbstractConfiguredObject<RemoteHostAddressImpl> implements RemoteHostAddress<RemoteHostAddressImpl>
+{
+    @ManagedAttributeField
+    private String _address;
+    @ManagedAttributeField
+    private int _port;
+    @ManagedAttributeField
+    private String _hostName;
+    @ManagedAttributeField
+    private Protocol _protocol;
+    @ManagedAttributeField
+    private Transport _transport;
+    @ManagedAttributeField
+    private KeyStore _keyStore;
+    @ManagedAttributeField
+    private Collection<TrustStore> _trustStores;
+    @ManagedAttributeField
+    private int _desiredHeartbeatInterval;
+
+    private List<String> _tlsProtocolBlackList;
+    private List<String> _tlsProtocolWhiteList;
+
+    private List<String> _tlsCipherSuiteWhiteList;
+    private List<String> _tlsCipherSuiteBlackList;
+
+
+    @ManagedObjectFactoryConstructor
+    public RemoteHostAddressImpl(Map<String, Object> attributes, RemoteHost<?> remoteHost)
+    {
+        super(parentsMap(remoteHost), attributes);
+    }
+
+
+    @Override
+    protected void onOpen()
+    {
+        super.onOpen();
+        _tlsProtocolWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_WHITE_LIST);
+        _tlsProtocolBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_PROTOCOL_BLACK_LIST);
+        _tlsCipherSuiteWhiteList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_WHITE_LIST);
+        _tlsCipherSuiteBlackList = getContextValue(List.class, ParameterizedTypes.LIST_OF_STRINGS, CommonProperties.QPID_SECURITY_TLS_CIPHER_SUITE_BLACK_LIST);
+    }
+
+
+    @Override
+    public String getAddress()
+    {
+        return _address;
+    }
+
+    @Override
+    public int getPort()
+    {
+        return _port;
+    }
+
+    @Override
+    public String getHostName()
+    {
+        return _hostName;
+    }
+
+    @Override
+    public Protocol getProtocol()
+    {
+        return _protocol;
+    }
+
+    @Override
+    public Transport getTransport()
+    {
+        return _transport;
+    }
+
+    @Override
+    public KeyStore getKeyStore()
+    {
+        return _keyStore;
+    }
+
+    @Override
+    public Collection<TrustStore> getTrustStores()
+    {
+        return _trustStores;
+    }
+
+    @Override
+    public int getDesiredHeartbeatInterval()
+    {
+        return _desiredHeartbeatInterval;
+    }
+
+    @Override
+    public List<String> getTlsProtocolWhiteList()
+    {
+        return _tlsProtocolWhiteList;
+    }
+
+    @Override
+    public List<String> getTlsProtocolBlackList()
+    {
+        return _tlsProtocolBlackList;
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteWhiteList()
+    {
+        return _tlsCipherSuiteWhiteList;
+    }
+
+    @Override
+    public List<String> getTlsCipherSuiteBlackList()
+    {
+        return _tlsCipherSuiteBlackList;
+    }
+
+    @StateTransition( currentState = {State.UNINITIALIZED, State.QUIESCED, State.ERRORED}, desiredState = State.ACTIVE )
+    protected ListenableFuture<Void> activate()
+    {
+        try
+        {
+            setState(State.ACTIVE);
+        }
+        catch (RuntimeException e)
+        {
+            setState(State.ERRORED);
+            throw new IllegalConfigurationException("Unable to active remote host address '" + getName() + "'", e);
+        }
+        return Futures.immediateFuture(null);
+    }
+
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/federation/RemoteHostImpl.java b/broker-core/src/main/java/org/apache/qpid/server/federation/RemoteHostImpl.java
new file mode 100644
index 0000000..cd369b9
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/RemoteHostImpl.java
@@ -0,0 +1,233 @@
+/*
+ *
+ * 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.federation;
+
+import java.security.AccessControlContext;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
+import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.RemoteHost;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.StateTransition;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.util.Action;
+import org.apache.qpid.server.virtualhost.HouseKeepingTask;
+
+@ManagedObject( category = false, type = RemoteHost.REMOTE_HOST_TYPE )
+class RemoteHostImpl extends AbstractConfiguredObject<RemoteHostImpl> implements RemoteHost<RemoteHostImpl>
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(RemoteHostImpl.class);
+
+    private final VirtualHost<?> _virtualHost;
+    @ManagedAttributeField
+    private int _retryPeriod;
+
+    @ManagedAttributeField
+    private boolean _redirectFollowed;
+
+    @ManagedAttributeField
+    private Collection<String> _routableAddresses;
+
+    private final AccessControlContext _createConnectionContext;
+    private final CreateConnectionTask _createConnectionTask;
+
+    enum ConnectionState
+    {
+        DISCONNECTED,
+        CONNECTING,
+        CONNECTED,
+        STOPPED
+    }
+
+    private ConnectionState _connectionState = ConnectionState.STOPPED;
+
+    @ManagedObjectFactoryConstructor
+    public RemoteHostImpl(Map<String, Object> attributes, VirtualHost<?> virtualHost)
+    {
+        super(parentsMap(virtualHost), attributes);
+        _virtualHost = virtualHost;
+        _createConnectionContext =
+                getSystemTaskControllerContext("Create connection " + getName(), _virtualHost.getPrincipal());
+        _createConnectionTask = new CreateConnectionTask();
+    }
+
+    @Override
+    public int getRetryPeriod()
+    {
+        return _retryPeriod;
+    }
+
+    @Override
+    public boolean isRedirectFollowed()
+    {
+        return _redirectFollowed;
+    }
+
+    @Override
+    public Collection<String> getRoutableAddresses()
+    {
+        return _routableAddresses;
+    }
+
+    @StateTransition(currentState = {State.UNINITIALIZED, State.ERRORED, State.STOPPED}, desiredState = State.ACTIVE)
+    private ListenableFuture<Void> onActivate()
+    {
+        setState(State.ACTIVE);
+        _failoverIterator = null;
+        if (_virtualHost.getState() == State.ACTIVE)
+        {
+            _createConnectionTask.scheduleNow();
+        }
+        else if (_virtualHost.getDesiredState() == State.ACTIVE)
+        {
+            _virtualHost.addChangeListener(new AbstractConfigurationChangeListener()
+            {
+                @Override
+                public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
+                {
+                    if (newState == State.ACTIVE)
+                    {
+
+                        _createConnectionTask.scheduleNow();
+
+                        _virtualHost.removeChangeListener(this);
+                    }
+                    else if (object.getDesiredState() != State.ACTIVE)
+                    {
+                        _virtualHost.removeChangeListener(this);
+                    }
+                }
+            });
+        }
+        return Futures.immediateFuture(null);
+    }
+
+    private Iterator<RemoteHostAddress> _failoverIterator;
+
+
+    private void setConnectionState(ConnectionState connectionState)
+    {
+        _connectionState = connectionState;
+    }
+
+    private synchronized void makeConnection()
+    {
+        LOGGER.debug("makeConnection called with state: {}, connectionState: {}", getState(), _connectionState);
+        if(getState() == State.ACTIVE && !EnumSet.of(ConnectionState.CONNECTED, ConnectionState.CONNECTING).contains(_connectionState))
+        {
+            if (_failoverIterator == null || !_failoverIterator.hasNext())
+            {
+                _failoverIterator = getChildren(RemoteHostAddress.class).iterator();
+            }
+            if (_failoverIterator.hasNext())
+            {
+                RemoteHostAddress<?> address = _failoverIterator.next();
+                setConnectionState(ConnectionState.CONNECTING);
+                boolean connected = _virtualHost.makeConnection(address, new Action<Boolean>()
+                {
+
+                    @Override
+                    public void performAction(final Boolean wasConnected)
+                    {
+                        setConnectionState(ConnectionState.DISCONNECTED);
+                        if (wasConnected)
+                        {
+                            _failoverIterator = null;
+                            _createConnectionTask.scheduleNow();
+                        }
+                        else if (_failoverIterator.hasNext())
+                        {
+                            _createConnectionTask.scheduleNow();
+                        }
+                        else
+                        {
+                            _createConnectionTask.schedule(1000L * _retryPeriod);
+                        }
+                    }
+                });
+
+                if (connected)
+                {
+                    setConnectionState(ConnectionState.CONNECTED);
+                }
+                else
+                {
+                    setConnectionState(ConnectionState.DISCONNECTED);
+                    if (_failoverIterator.hasNext())
+                    {
+                        _createConnectionTask.scheduleNow();
+                    }
+                    else
+                    {
+                        _createConnectionTask.schedule(1000L * _retryPeriod);
+                    }
+                }
+            }
+        }
+
+    }
+
+    private class CreateConnectionTask extends HouseKeepingTask
+    {
+
+        private final AtomicBoolean _scheduled = new AtomicBoolean();
+
+        public CreateConnectionTask()
+        {
+            super("Create connection: " + RemoteHostImpl.this.getName(), _virtualHost, _createConnectionContext);
+        }
+
+        @Override
+        public void execute()
+        {
+            _scheduled.set(false);
+            makeConnection();
+        }
+
+        public void schedule(long delay)
+        {
+            if(_scheduled.compareAndSet(false, true))
+            {
+                _virtualHost.scheduleTask(delay, this);
+            }
+        }
+
+        public void scheduleNow()
+        {
+            schedule(0L);
+        }
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/federation/UsernamePasswordCredentialImpl.java b/broker-core/src/main/java/org/apache/qpid/server/federation/UsernamePasswordCredentialImpl.java
new file mode 100644
index 0000000..ecf1f67
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/UsernamePasswordCredentialImpl.java
@@ -0,0 +1,88 @@
+/*
+ *
+ * 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.federation;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.security.sasl.SaslClient;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.apache.qpid.server.federation.sasl.ScramSHA1SaslClient;
+import org.apache.qpid.server.federation.sasl.ScramSHA256SaslClient;
+import org.apache.qpid.server.model.AbstractConfiguredObject;
+import org.apache.qpid.server.model.ManagedAttributeField;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.model.RemoteHost;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.StateTransition;
+import org.apache.qpid.server.model.UsernamePasswordCredential;
+
+class UsernamePasswordCredentialImpl extends AbstractConfiguredObject<UsernamePasswordCredentialImpl>
+        implements UsernamePasswordCredential<UsernamePasswordCredentialImpl>
+{
+    @ManagedAttributeField
+    private String _username;
+    @ManagedAttributeField
+    private String _password;
+
+    @ManagedObjectFactoryConstructor
+    UsernamePasswordCredentialImpl(Map<String, Object> attributes, RemoteHost<?> host)
+    {
+        super(parentsMap(host), attributes);
+    }
+
+        @Override
+    public SaslClient getSaslClient(final List<String> mechanisms)
+    {
+        if(mechanisms.contains(ScramSHA256SaslClient.MECHANISM))
+        {
+            return new ScramSHA256SaslClient(this);
+        }
+        else if(mechanisms.contains(ScramSHA1SaslClient.MECHANISM))
+        {
+            return new ScramSHA1SaslClient(this);
+        }
+        return null;
+    }
+
+    @Override
+    public String getUsername()
+    {
+        return _username;
+    }
+
+    @Override
+    public String getPassword()
+    {
+        return _password;
+    }
+
+    @StateTransition( currentState = {State.UNINITIALIZED, State.QUIESCED, State.ERRORED}, desiredState = State.ACTIVE )
+    protected ListenableFuture<Void> activate()
+    {
+        setState(State.ACTIVE);
+        return Futures.immediateFuture(null);
+    }
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/AbstractScramSaslClient.java b/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/AbstractScramSaslClient.java
new file mode 100644
index 0000000..ac7d9ef
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/AbstractScramSaslClient.java
@@ -0,0 +1,323 @@
+/*
+ *
+ * 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.federation.sasl;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.UUID;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.qpid.server.model.UsernamePasswordCredential;
+
+public abstract class AbstractScramSaslClient implements SaslClient
+{
+
+    private static final byte[] INT_1 = new byte[]{0, 0, 0, 1};
+    private static final String GS2_HEADER = "n,,";
+    private static final Charset ASCII = Charset.forName("ASCII");
+
+    private final String _digestName;
+    private final String _hmacName;
+
+    private String _username;
+    private final String _clientNonce = UUID.randomUUID().toString();
+    private String _serverNonce;
+    private byte[] _salt;
+    private int _iterationCount;
+    private String _clientFirstMessageBare;
+    private byte[] _serverSignature;
+
+    enum State
+    {
+        INITIAL,
+        CLIENT_FIRST_SENT,
+        CLIENT_PROOF_SENT,
+        COMPLETE
+    }
+
+    public final String _mechanism;
+
+    private final UsernamePasswordCredential<?> _credentials;
+
+    private State _state = State.INITIAL;
+
+    public AbstractScramSaslClient(final UsernamePasswordCredential credentials,
+                                   final String mechanism,
+                                   final String digestName,
+                                   final String hmacName)
+    {
+        _mechanism = mechanism;
+        _digestName = digestName;
+        _hmacName = hmacName;
+        _credentials = credentials;
+
+    }
+
+    @Override
+    public String getMechanismName()
+    {
+        return _mechanism;
+    }
+
+    @Override
+    public boolean hasInitialResponse()
+    {
+        return true;
+    }
+
+    @Override
+    public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
+    {
+        byte[] response;
+        switch(_state)
+        {
+            case INITIAL:
+                response = initialResponse();
+                _state = State.CLIENT_FIRST_SENT;
+                break;
+            case CLIENT_FIRST_SENT:
+                response = calculateClientProof(challenge);
+                _state = State.CLIENT_PROOF_SENT;
+                break;
+            case CLIENT_PROOF_SENT:
+                evaluateOutcome(challenge);
+                response = new byte[0];
+                _state = State.COMPLETE;
+                break;
+            default:
+                throw new SaslException("No challenge expected in state " + _state);
+        }
+        return response;
+    }
+
+    private void evaluateOutcome(final byte[] challenge) throws SaslException
+    {
+        String serverFinalMessage = new String(challenge, ASCII);
+        String[] parts = serverFinalMessage.split(",");
+        if(!parts[0].startsWith("v="))
+        {
+            throw new SaslException("Server final message did not contain verifier");
+        }
+        byte[] serverSignature = DatatypeConverter.parseBase64Binary(parts[0].substring(2));
+        if(!Arrays.equals(_serverSignature, serverSignature))
+        {
+            throw new SaslException("Server signature did not match");
+        }
+    }
+
+    private byte[] calculateClientProof(final byte[] challenge) throws SaslException
+    {
+        try
+        {
+            String serverFirstMessage = new String(challenge, ASCII);
+            String[] parts = serverFirstMessage.split(",");
+            if(parts.length < 3)
+            {
+                throw new SaslException("Server challenge '" + serverFirstMessage + "' cannot be parsed");
+            }
+            else if(parts[0].startsWith("m="))
+            {
+                throw new SaslException("Server requires mandatory extension which is not supported: " + parts[0]);
+            }
+            else if(!parts[0].startsWith("r="))
+            {
+                throw new SaslException("Server challenge '" + serverFirstMessage + "' cannot be parsed, cannot find nonce");
+            }
+            String nonce = parts[0].substring(2);
+            if(!nonce.startsWith(_clientNonce))
+            {
+                throw new SaslException("Server challenge did not use correct client nonce");
+            }
+            _serverNonce = nonce;
+            if(!parts[1].startsWith("s="))
+            {
+                throw new SaslException("Server challenge '" + serverFirstMessage + "' cannot be parsed, cannot find salt");
+            }
+            String base64Salt = parts[1].substring(2);
+            _salt = DatatypeConverter.parseBase64Binary(base64Salt);
+            if(!parts[2].startsWith("i="))
+            {
+                throw new SaslException("Server challenge '" + serverFirstMessage + "' cannot be parsed, cannot find iteration count");
+            }
+            String iterCountString = parts[2].substring(2);
+            _iterationCount = Integer.parseInt(iterCountString);
+            if(_iterationCount <= 0)
+            {
+                throw new SaslException("Iteration count " + _iterationCount + " is not a positive integer");
+            }
+            byte[] passwordBytes = saslPrep(_credentials.getPassword()).getBytes("UTF-8");
+
+            byte[] saltedPassword = generateSaltedPassword(passwordBytes);
+
+
+            String clientFinalMessageWithoutProof =
+                    "c=" + DatatypeConverter.printBase64Binary(GS2_HEADER.getBytes(ASCII))
+                    + ",r=" + _serverNonce;
+
+            String authMessage = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof;
+
+            byte[] clientKey = computeHmac(saltedPassword, "Client Key");
+            byte[] storedKey = MessageDigest.getInstance(_digestName).digest(clientKey);
+
+            byte[] clientSignature = computeHmac(storedKey, authMessage);
+
+            byte[] clientProof = clientKey.clone();
+            for(int i = 0 ; i < clientProof.length; i++)
+            {
+                clientProof[i] ^= clientSignature[i];
+            }
+            byte[] serverKey = computeHmac(saltedPassword, "Server Key");
+            _serverSignature = computeHmac(serverKey, authMessage);
+
+            String finalMessageWithProof = clientFinalMessageWithoutProof
+                                           + ",p=" + DatatypeConverter.printBase64Binary(clientProof);
+            return finalMessageWithProof.getBytes();
+        }
+        catch (IllegalArgumentException | NoSuchAlgorithmException | IOException e)
+        {
+            throw new SaslException(e.getMessage(), e);
+        }
+    }
+
+    private byte[] computeHmac(final byte[] key, final String string)
+            throws SaslException, UnsupportedEncodingException
+    {
+        Mac mac = createHmac(key);
+        mac.update(string.getBytes(ASCII));
+        return mac.doFinal();
+    }
+
+    private byte[] generateSaltedPassword(final byte[] passwordBytes) throws SaslException
+    {
+        Mac mac = createHmac(passwordBytes);
+
+        mac.update(_salt);
+        mac.update(INT_1);
+        byte[] result = mac.doFinal();
+
+        byte[] previous = null;
+        for(int i = 1; i < _iterationCount; i++)
+        {
+            mac.update(previous != null? previous: result);
+            previous = mac.doFinal();
+            for(int x = 0; x < result.length; x++)
+            {
+                result[x] ^= previous[x];
+            }
+        }
+
+        return result;
+    }
+
+    private Mac createHmac(final byte[] keyBytes)
+            throws SaslException
+    {
+        try
+        {
+            SecretKeySpec key = new SecretKeySpec(keyBytes, _hmacName);
+            Mac mac = Mac.getInstance(_hmacName);
+            mac.init(key);
+            return mac;
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new SaslException(e.getMessage(), e);
+        }
+        catch (InvalidKeyException e)
+        {
+            throw new SaslException(e.getMessage(), e);
+        }
+    }
+
+
+    private byte[] initialResponse() throws SaslException
+    {
+        try
+        {
+            StringBuffer buf = new StringBuffer("n=");
+            _username = _credentials.getUsername();
+            buf.append(saslPrep(_username));
+            buf.append(",r=");
+            buf.append(_clientNonce);
+            _clientFirstMessageBare = buf.toString();
+            return (GS2_HEADER + _clientFirstMessageBare).getBytes(ASCII);
+        }
+        catch (IOException e)
+        {
+            throw new SaslException(e.getMessage(), e);
+        }
+    }
+
+    private String saslPrep(String name) throws SaslException
+    {
+        // TODO - a real implementation of SaslPrep
+
+        if(!ASCII.newEncoder().canEncode(name))
+        {
+            throw new SaslException("Can only encode names and passwords which are restricted to ASCII characters");
+        }
+
+        name = name.replace("=", "=3D");
+        name = name.replace(",", "=2C");
+        return name;
+    }
+
+    @Override
+    public boolean isComplete()
+    {
+        return _state == State.COMPLETE;
+    }
+
+    @Override
+    public byte[] unwrap(final byte[] incoming, final int offset, final int len) throws SaslException
+    {
+        throw new IllegalStateException("No security layer supported");
+    }
+
+    @Override
+    public byte[] wrap(final byte[] outgoing, final int offset, final int len) throws SaslException
+    {
+        throw new IllegalStateException("No security layer supported");
+    }
+
+    @Override
+    public Object getNegotiatedProperty(final String propName)
+    {
+        return null;
+    }
+
+    @Override
+    public void dispose() throws SaslException
+    {
+
+    }
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/ScramSHA1SaslClient.java
similarity index 67%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/federation/sasl/ScramSHA1SaslClient.java
index d2aff53..8a2297d 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/ScramSHA1SaslClient.java
@@ -18,8 +18,17 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.federation.sasl;
 
-public interface QueueEntryListBase extends QueueEntryList
+import org.apache.qpid.server.model.UsernamePasswordCredential;
+
+public class ScramSHA1SaslClient extends AbstractScramSaslClient
 {
+
+    public static final String MECHANISM = "SCRAM-SHA-1";
+
+    public ScramSHA1SaslClient(final UsernamePasswordCredential<?> credentials)
+    {
+        super(credentials, MECHANISM, "SHA-1", "HmacSHA1");
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/ScramSHA256SaslClient.java
similarity index 66%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/federation/sasl/ScramSHA256SaslClient.java
index d2aff53..40b4872 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/federation/sasl/ScramSHA256SaslClient.java
@@ -18,8 +18,17 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.federation.sasl;
 
-public interface QueueEntryListBase extends QueueEntryList
+import org.apache.qpid.server.model.UsernamePasswordCredential;
+
+public class ScramSHA256SaslClient extends AbstractScramSaslClient
 {
+
+    public static final String MECHANISM = "SCRAM-SHA-256";
+
+    public ScramSHA256SaslClient(final UsernamePasswordCredential<?> credentials)
+    {
+        super(credentials, MECHANISM, "SHA-256", "HmacSHA256");
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java b/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java
index ba724d8..b570a6a 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/filter/FilterSupport.java
@@ -31,10 +31,9 @@
 import org.apache.qpid.filter.SelectorParsingException;
 import org.apache.qpid.filter.selector.ParseException;
 import org.apache.qpid.filter.selector.TokenMgrError;
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.model.Queue;
 import org.apache.qpid.server.plugin.PluggableService;
+import org.apache.qpid.server.queue.QueueConsumer;
 
 public class FilterSupport
 {
@@ -119,9 +118,9 @@
     @PluggableService
     public static final class NoLocalFilter implements MessageFilter
     {
-        private final MessageSource _queue;
+        private final Queue<?> _queue;
 
-        private NoLocalFilter(MessageSource queue)
+        private NoLocalFilter(Queue<?> queue)
         {
             _queue = queue;
         }
@@ -135,8 +134,8 @@
         public boolean matches(Filterable message)
         {
 
-            final Collection<? extends ConsumerImpl> consumers = _queue.getConsumers();
-            for(ConsumerImpl c : consumers)
+            final Collection<QueueConsumer<?>> consumers = _queue.getConsumers();
+            for(QueueConsumer<?> c : consumers)
             {
                 if(c.getSessionModel().getConnectionReference() == message.getConnectionReference())
                 {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java b/broker-core/src/main/java/org/apache/qpid/server/message/AcquiringMessageInstanceConsumer.java
similarity index 68%
copy from broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
copy to broker-core/src/main/java/org/apache/qpid/server/message/AcquiringMessageInstanceConsumer.java
index 7ca5c6d..1249127 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/AcquiringMessageInstanceConsumer.java
@@ -20,9 +20,17 @@
  */
 package org.apache.qpid.server.message;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.queue.QueueEntry;
 
-public interface MessageSourceConsumer<X extends MessageSourceConsumer<X>> extends ConsumerImpl, Consumer<MessageSourceConsumer<X>>
+public interface AcquiringMessageInstanceConsumer<X extends AcquiringMessageInstanceConsumer<X, T>, T> extends MessageInstanceConsumer
 {
+    MessageInstance.StealableConsumerAcquiredState<X> getOwningState();
+
+    T getTarget();
+
+    void acquisitionRemoved(QueueEntry queueEntry);
+
+    long getConsumerNumber();
+
+    boolean resend(QueueEntry queueEntry);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java b/broker-core/src/main/java/org/apache/qpid/server/message/BaseMessageInstance.java
similarity index 70%
copy from broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
copy to broker-core/src/main/java/org/apache/qpid/server/message/BaseMessageInstance.java
index 7ca5c6d..f9a9e74 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/BaseMessageInstance.java
@@ -20,9 +20,20 @@
  */
 package org.apache.qpid.server.message;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.store.TransactionLogResource;
 
-public interface MessageSourceConsumer<X extends MessageSourceConsumer<X>> extends ConsumerImpl, Consumer<MessageSourceConsumer<X>>
+public interface BaseMessageInstance
 {
+    boolean getDeliveredToConsumer();
+
+    ServerMessage getMessage();
+
+    TransactionLogResource getOwningResource();
+
+    MessageEnqueueRecord getEnqueueRecord();
+
+    boolean acquire();
+
+    void delete();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/message/ConsumerOption.java
similarity index 83%
rename from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
rename to broker-core/src/main/java/org/apache/qpid/server/message/ConsumerOption.java
index d2aff53..7bbcf15 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/ConsumerOption.java
@@ -18,8 +18,14 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.message;
 
-public interface QueueEntryListBase extends QueueEntryList
+public enum ConsumerOption
 {
+    ACQUIRES,
+    SEES_REQUEUES,
+    TRANSIENT,
+    EXCLUSIVE,
+    NO_LOCAL,
+    DURABLE
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java b/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java
index 91035be..9034fc4 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/MessageDestination.java
@@ -53,5 +53,5 @@
                                                                           final String routingAddress,
                                                                           InstanceProperties instanceProperties,
                                                                           ServerTransaction txn,
-                                                                          Action<? super MessageInstance> postEnqueueAction);
+                                                                          Action<? super BaseMessageInstance> postEnqueueAction);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageInfoImpl.java b/broker-core/src/main/java/org/apache/qpid/server/message/MessageInfoImpl.java
index 3750711..2cafde9 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageInfoImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/MessageInfoImpl.java
@@ -55,7 +55,7 @@
         final AMQMessageHeader messageHeader = message.getMessageHeader();
 
         _deliveredTo = instance.getDeliveredConsumer() == null ? null : String.valueOf(instance.getDeliveredConsumer()
-                                                                                                .getConsumerNumber());
+                                                                                                .getIdentifier());
         _arrivalTime = message.getArrivalTime() == 0L ? null : new Date(message.getArrivalTime());
         _persistent = message.isPersistent();
         _messageId = messageHeader.getMessageId();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java b/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java
index ed6724e..cec2f83 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstance.java
@@ -21,15 +21,12 @@
 package org.apache.qpid.server.message;
 
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.filter.Filterable;
-import org.apache.qpid.server.store.MessageEnqueueRecord;
-import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.server.txn.ServerTransaction;
 import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.util.StateChangeListener;
 
-public interface MessageInstance
+public interface MessageInstance extends BaseMessageInstance
 {
 
 
@@ -50,39 +47,37 @@
 
     boolean acquiredByConsumer();
 
-    boolean isAcquiredBy(ConsumerImpl consumer);
+    boolean isAcquiredBy(MessageInstanceConsumer consumer);
 
-    boolean removeAcquisitionFromConsumer(ConsumerImpl consumer);
+    boolean removeAcquisitionFromConsumer(MessageInstanceConsumer consumer);
 
     void setRedelivered();
 
     boolean isRedelivered();
 
-    ConsumerImpl getDeliveredConsumer();
+    MessageInstanceConsumer getDeliveredConsumer();
 
     void reject();
 
-    boolean isRejectedBy(ConsumerImpl consumer);
-
-    boolean getDeliveredToConsumer();
+    boolean isRejectedBy(MessageInstanceConsumer consumer);
 
     boolean expired();
 
-    boolean acquire(ConsumerImpl sub);
+    boolean acquire(MessageInstanceConsumer sub);
 
-    boolean makeAcquisitionUnstealable(final ConsumerImpl consumer);
+    boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer);
 
     boolean makeAcquisitionStealable();
 
     int getMaximumDeliveryCount();
 
-    int routeToAlternate(Action<? super MessageInstance> action, ServerTransaction txn);
+    int routeToAlternate(Action<? super BaseMessageInstance> action, ServerTransaction txn);
 
     Filterable asFilterable();
 
-    ConsumerImpl getAcquiringConsumer();
+    MessageInstanceConsumer getAcquiringConsumer();
 
-    MessageEnqueueRecord getEnqueueRecord();
+    InstanceProperties getInstanceProperties();
 
     enum State
     {
@@ -171,7 +166,7 @@
         }
     }
 
-    abstract class ConsumerAcquiredState<C extends ConsumerImpl> extends EntryState
+    abstract class ConsumerAcquiredState<C extends AcquiringMessageInstanceConsumer<C,?>> extends EntryState
     {
         public abstract C getConsumer();
 
@@ -188,7 +183,7 @@
         }
     }
 
-    final class StealableConsumerAcquiredState<C extends ConsumerImpl> extends ConsumerAcquiredState
+    final class StealableConsumerAcquiredState<C extends AcquiringMessageInstanceConsumer<C,?>> extends ConsumerAcquiredState
     {
         private final C _consumer;
         private final UnstealableConsumerAcquiredState<C> _unstealableState;
@@ -211,7 +206,7 @@
         }
     }
 
-    final class UnstealableConsumerAcquiredState<C extends ConsumerImpl> extends ConsumerAcquiredState
+    final class UnstealableConsumerAcquiredState<C extends AcquiringMessageInstanceConsumer<C,?>> extends ConsumerAcquiredState
     {
         private final StealableConsumerAcquiredState<C> _stealableState;
 
@@ -240,25 +235,15 @@
 
     boolean isAvailable();
 
-    boolean acquire();
-
     boolean isAcquired();
 
     void release();
 
-    void release(ConsumerImpl release);
+    void release(MessageInstanceConsumer release);
 
     boolean resend();
 
-    void delete();
-
     boolean isDeleted();
 
     boolean isHeld();
-
-    ServerMessage getMessage();
-
-    InstanceProperties getInstanceProperties();
-
-    TransactionLogResource getOwningResource();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java b/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstanceConsumer.java
similarity index 75%
rename from broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
rename to broker-core/src/main/java/org/apache/qpid/server/message/MessageInstanceConsumer.java
index 7ca5c6d..4d645d4 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/MessageInstanceConsumer.java
@@ -20,9 +20,24 @@
  */
 package org.apache.qpid.server.message;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.model.Consumer;
-
-public interface MessageSourceConsumer<X extends MessageSourceConsumer<X>> extends ConsumerImpl, Consumer<MessageSourceConsumer<X>>
+public interface MessageInstanceConsumer
 {
+
+    boolean isClosed();
+
+    boolean acquires();
+
+    String getName();
+
+    void close();
+
+    void flush();
+
+    void externalStateChange();
+
+    Object getIdentifier();
+
+    boolean hasAvailableMessages();
+
+    void pullMessage();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java b/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java
index 3812474..f1c79d4 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/message/MessageSource.java
@@ -23,23 +23,22 @@
 import java.util.Collection;
 import java.util.EnumSet;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.FilterManager;
 import org.apache.qpid.server.protocol.AMQSessionModel;
 import org.apache.qpid.server.store.TransactionLogResource;
 
-public interface MessageSource extends TransactionLogResource, MessageNode
+public interface MessageSource<X extends MessageInstanceConsumer> extends TransactionLogResource, MessageNode
 {
-     ConsumerImpl addConsumer(ConsumerTarget target, FilterManager filters,
-                              Class<? extends ServerMessage> messageClass,
-                              String consumerName,
-                              EnumSet<ConsumerImpl.Option> options,
-                              Integer priority)
-            throws ExistingExclusiveConsumer, ExistingConsumerPreventsExclusive,
-                   ConsumerAccessRefused;
+    X addConsumer(ConsumerTarget target,
+                  FilterManager filters,
+                  Class<? extends ServerMessage> messageClass,
+                  String consumerName,
+                  EnumSet<ConsumerOption> options,
+                  Integer priority)
+            throws ExistingExclusiveConsumer, ExistingConsumerPreventsExclusive, ConsumerAccessRefused;
 
-    Collection<? extends ConsumerImpl> getConsumers();
+    Collection<X> getConsumers();
 
     boolean verifySessionAccess(AMQSessionModel<?> session);
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/NoopConfigurationChangeListener.java b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfigurationChangeListener.java
similarity index 93%
rename from broker-core/src/main/java/org/apache/qpid/server/model/NoopConfigurationChangeListener.java
rename to broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfigurationChangeListener.java
index 4c22583..a722edb 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/NoopConfigurationChangeListener.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfigurationChangeListener.java
@@ -20,7 +20,7 @@
  */
 package org.apache.qpid.server.model;
 
-public class NoopConfigurationChangeListener implements ConfigurationChangeListener
+public abstract class AbstractConfigurationChangeListener implements ConfigurationChangeListener
 {
     @Override
     public void stateChanged(ConfiguredObject<?> object, State oldState, State newState)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
index 2b16dd8..7e219f3 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java
@@ -2596,11 +2596,11 @@
     public ListenableFuture<Void> setAttributesAsync(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException, IllegalArgumentException
     {
         final Map<String,Object> updateAttributes = new HashMap<>(attributes);
-        Object desiredState = updateAttributes.remove(ConfiguredObject.DESIRED_STATE);
-        runTask(new Task<Void, RuntimeException>()
+        final Object desiredState = updateAttributes.remove(ConfiguredObject.DESIRED_STATE);
+        return doOnConfigThread(new Task<ListenableFuture<Void>, RuntimeException>()
         {
             @Override
-            public Void execute()
+            public ListenableFuture<Void> execute()
             {
                 authoriseSetAttributes(createProxyForValidation(attributes), attributes.keySet());
                 if (!isSystemProcess())
@@ -2609,7 +2609,29 @@
                 }
 
                 changeAttributes(updateAttributes);
-                return null;
+                if(desiredState != null)
+                {
+                    State state;
+                    if(desiredState instanceof State)
+                    {
+                        state = (State)desiredState;
+                    }
+                    else if(desiredState instanceof String)
+                    {
+                        state = State.valueOf((String)desiredState);
+                    }
+                    else
+                    {
+                        throw new IllegalArgumentException("Cannot convert an object of type " + desiredState.getClass().getName() + " to a State");
+                    }
+                    return setDesiredState(state);
+                }
+                else
+                {
+                    return Futures.immediateFuture(null);
+                }
+
+
             }
 
             @Override
@@ -2630,27 +2652,6 @@
                 return "attributes number=" + attributes.size();
             }
         });
-        if(desiredState != null)
-        {
-            State state;
-            if(desiredState instanceof State)
-            {
-                state = (State)desiredState;
-            }
-            else if(desiredState instanceof String)
-            {
-                state = State.valueOf((String)desiredState);
-            }
-            else
-            {
-                throw new IllegalArgumentException("Cannot convert an object of type " + desiredState.getClass().getName() + " to a State");
-            }
-            return setDesiredState(state);
-        }
-        else
-        {
-            return Futures.immediateFuture(null);
-        }
     }
 
     public void forceUpdateAllSecureAttributes()
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java
index 8411476..f84f9c7 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/AbstractSystemConfig.java
@@ -469,11 +469,13 @@
         return preferenceStoreFactory.createInstance(this, attributes);
     }
 
+    @Override
     protected final Principal getSystemPrincipal()
     {
         return _systemPrincipal;
     }
 
+    @Override
     public Runnable getOnContainerResolveTask()
     {
         return _onContainerResolveTask;
@@ -485,11 +487,13 @@
         _onContainerResolveTask = onContainerResolveTask;
     }
 
+    @Override
     public Runnable getOnContainerCloseTask()
     {
         return _onContainerCloseTask;
     }
 
+    @Override
     public void setOnContainerCloseTask(final Runnable onContainerCloseTask)
     {
         _onContainerCloseTask = onContainerCloseTask;
@@ -497,6 +501,7 @@
 
     private class ShutdownService implements Runnable
     {
+        @Override
         public void run()
         {
             Subject.doAs(getSystemTaskSubject("Shutdown"),
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/model/AnonymousCredential.java
similarity index 76%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/model/AnonymousCredential.java
index d2aff53..2955103 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/AnonymousCredential.java
@@ -18,8 +18,12 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.model;
 
-public interface QueueEntryListBase extends QueueEntryList
+@ManagedObject(category = false, type = AnonymousCredential.ANONYMOUS)
+public interface AnonymousCredential<X extends AnonymousCredential<X>> extends Credential<X>
 {
+    String ANONYMOUS = "Anonymous";
+
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerImpl.java b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerImpl.java
index 452e260..226ba15 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerImpl.java
@@ -1105,17 +1105,11 @@
     }
 
 
-    private final class AccessControlProviderListener implements ConfigurationChangeListener
+    private final class AccessControlProviderListener extends AbstractConfigurationChangeListener
     {
         private final Set<ConfiguredObject<?>> _bulkChanges = new HashSet<>();
 
         @Override
-        public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
-        {
-
-        }
-
-        @Override
         public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
         {
             if(object.getCategoryClass() == Broker.class && child.getCategoryClass() == AccessControlProvider.class)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java
index bc57081..c347723 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/BrokerModel.java
@@ -96,6 +96,11 @@
         addRelationship(VirtualHost.class, VirtualHostAccessControlProvider.class);
         addRelationship(VirtualHost.class, Exchange.class);
         addRelationship(VirtualHost.class, Queue.class);
+        addRelationship(VirtualHost.class, RemoteHost.class);
+
+
+        addRelationship(RemoteHost.class, RemoteHostAddress.class);
+        addRelationship(RemoteHost.class, Credential.class);
 
         addRelationship(VirtualHostLogger.class, VirtualHostLogInclusionRule.class);
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
index 8a54297..1866d5d 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ConfiguredObject.java
@@ -40,7 +40,8 @@
 /**
  * An object that can be "managed" (eg via the web interface) and usually read from configuration.
  */
-public interface ConfiguredObject<X extends ConfiguredObject<X>> extends ContextProvider, TaskExecutorProvider, PermissionedObject
+public interface ConfiguredObject<X extends ConfiguredObject<X>> extends ContextProvider, TaskExecutorProvider,
+                                                                         PermissionedObject
 {
     String OVER_SIZED_ATTRIBUTE_ALTERNATIVE_TEXT = "Value is too long to display";
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java b/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
index 3244cdd..a1df8b4 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Consumer.java
@@ -20,10 +20,12 @@
  */
 package org.apache.qpid.server.model;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.qpid.server.protocol.AMQSessionModel;
 
 @ManagedObject
-public interface Consumer<X extends Consumer<X>> extends ConfiguredObject<X>, ConsumerImpl
+public interface Consumer<X extends Consumer<X>> extends ConfiguredObject<X>
 {
     String DISTRIBUTION_MODE = "distributionMode";
     String EXCLUSIVE = "exclusive";
@@ -36,7 +38,7 @@
     String SUSPEND_NOTIFICATION_PERIOD = "consumer.suspendNotificationPeriod";
 
     @ManagedContextDefault( name = SUSPEND_NOTIFICATION_PERIOD)
-    long SUSPEND_NOTIFICATION_PERIOD_DEFAULT = 10000;
+    long SUSPEND_NOTIFICATION_PERIOD_DEFAULT = 10000;AtomicLong CONSUMER_NUMBER_GENERATOR = new AtomicLong(0);
 
     @ManagedAttribute
     String getDistributionMode();
@@ -70,4 +72,21 @@
     @ManagedStatistic(statisticType = StatisticType.POINT_IN_TIME, units = StatisticUnit.MESSAGES, label = "Prefetch")
     long getUnacknowledgedMessages();
 
+
+    AMQSessionModel getSessionModel();
+
+    long getConsumerNumber();
+
+    boolean isSuspended();
+
+    boolean seesRequeues();
+
+    boolean trySendLock();
+
+
+    void getSendLock();
+
+    void releaseSendLock();
+
+    boolean isActive();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/model/Credential.java
similarity index 74%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/model/Credential.java
index d2aff53..0b9d405 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Credential.java
@@ -18,8 +18,15 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.model;
 
-public interface QueueEntryListBase extends QueueEntryList
+import java.util.List;
+
+import javax.security.sasl.SaslClient;
+
+@ManagedObject(creatable = false)
+public interface Credential<X extends Credential<X>> extends ConfiguredObject<X>
 {
+
+    SaslClient getSaslClient(List<String> mechanisms);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java b/broker-core/src/main/java/org/apache/qpid/server/model/ExternalCredential.java
similarity index 74%
copy from broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
copy to broker-core/src/main/java/org/apache/qpid/server/model/ExternalCredential.java
index 7ca5c6d..bf4dbff 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/ExternalCredential.java
@@ -18,11 +18,14 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.message;
+package org.apache.qpid.server.model;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.model.Consumer;
-
-public interface MessageSourceConsumer<X extends MessageSourceConsumer<X>> extends ConsumerImpl, Consumer<MessageSourceConsumer<X>>
+@ManagedObject(category = false, type = ExternalCredential.EXTERNAL)
+public interface ExternalCredential<X extends ExternalCredential<X>> extends Credential<X>
 {
+    String EXTERNAL = "External";
+
+    @ManagedAttribute
+    String getUsername();
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java b/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
index e1651e9..83e6c72 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/Queue.java
@@ -34,11 +34,11 @@
 import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.protocol.CapacityChecker;
-import org.apache.qpid.server.queue.BaseQueue;
 import org.apache.qpid.server.queue.NotificationCheck;
 import org.apache.qpid.server.queue.QueueConsumer;
 import org.apache.qpid.server.queue.QueueEntry;
 import org.apache.qpid.server.queue.QueueEntryVisitor;
+import org.apache.qpid.server.queue.RecoverableBaseQueue;
 import org.apache.qpid.server.store.MessageDurability;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.util.Deletable;
@@ -46,8 +46,8 @@
 @ManagedObject( defaultType = "standard", description = Queue.CLASS_DESCRIPTION )
 public interface Queue<X extends Queue<X>> extends ConfiguredObject<X>,
                                                    Comparable<X>, ExchangeReferrer,
-                                                   BaseQueue,
-                                                   MessageSource,
+                                                   RecoverableBaseQueue,
+                                                   MessageSource<QueueConsumer<?>>,
                                                    CapacityChecker,
                                                    MessageDestination,
                                                    Deletable<X>
@@ -237,7 +237,7 @@
     Collection<? extends Binding<?>> getBindings();
 
 
-    Collection<? extends Consumer<?>> getConsumers();
+    Collection<QueueConsumer<?>> getConsumers();
 
     //operations
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/model/RemoteHost.java
similarity index 62%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/model/RemoteHost.java
index d2aff53..a376837 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/RemoteHost.java
@@ -18,8 +18,23 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.model;
 
-public interface QueueEntryListBase extends QueueEntryList
+import java.util.Collection;
+
+@ManagedObject(defaultType = RemoteHost.REMOTE_HOST_TYPE)
+public interface RemoteHost<X extends RemoteHost<X>> extends ConfiguredObject<X>
 {
+
+    String REMOTE_HOST_TYPE = "Standard";
+
+    @ManagedAttribute(defaultValue = "10")
+    int getRetryPeriod();
+
+    @ManagedAttribute(defaultValue = "true")
+    boolean isRedirectFollowed();
+
+    @ManagedAttribute(defaultValue = "[]")
+    Collection<String> getRoutableAddresses();
+
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/RemoteHostAddress.java b/broker-core/src/main/java/org/apache/qpid/server/model/RemoteHostAddress.java
new file mode 100644
index 0000000..c017e81
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/RemoteHostAddress.java
@@ -0,0 +1,69 @@
+/*
+ *
+ * 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.model;
+
+import java.util.Collection;
+import java.util.List;
+
+@ManagedObject( defaultType = RemoteHostAddress.REMOTE_HOST_ADDRESS_TYPE)
+public interface RemoteHostAddress<X extends RemoteHostAddress<X>> extends ConfiguredObject<X>
+{
+
+    String REMOTE_HOST_ADDRESS_TYPE = "Standard";
+
+    @ManagedAttribute(mandatory = true)
+    String getAddress();
+
+    @ManagedAttribute(mandatory = true)
+    int getPort();
+
+    @ManagedAttribute
+    String getHostName();
+
+    @ManagedAttribute
+    Protocol getProtocol();
+
+    @ManagedAttribute( defaultValue = "TCP" )
+    Transport getTransport();
+
+    @ManagedAttribute
+    KeyStore getKeyStore();
+
+    @ManagedAttribute
+    Collection<TrustStore> getTrustStores();
+
+    @ManagedAttribute(defaultValue = "0")
+    int getDesiredHeartbeatInterval();
+
+
+    @DerivedAttribute
+    List<String> getTlsProtocolWhiteList();
+
+    @DerivedAttribute
+    List<String> getTlsProtocolBlackList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteWhiteList();
+
+    @DerivedAttribute
+    List<String> getTlsCipherSuiteBlackList();
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/model/UsernamePasswordCredential.java
similarity index 67%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/model/UsernamePasswordCredential.java
index d2aff53..dbb59da 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/UsernamePasswordCredential.java
@@ -18,8 +18,16 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.model;
 
-public interface QueueEntryListBase extends QueueEntryList
+@ManagedObject(category = false, type = UsernamePasswordCredential.USERNAME_PASSWORD)
+public interface UsernamePasswordCredential<X extends UsernamePasswordCredential<X>> extends Credential<X>
 {
+    String USERNAME_PASSWORD = "UsernamePassword";
+
+    @ManagedAttribute
+    String getUsername();
+
+    @ManagedAttribute(secure = true)
+    String getPassword();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java b/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java
index 720f96a..b0996f9 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/VirtualHost.java
@@ -37,7 +37,9 @@
 import org.apache.qpid.server.store.DurableConfigurationStore;
 import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.store.preferences.UserPreferencesCreator;
+import org.apache.qpid.server.transfer.TransferQueue;
 import org.apache.qpid.server.transport.AMQPConnection;
+import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.virtualhost.HouseKeepingTask;
 import org.apache.qpid.server.virtualhost.NodeAutoCreationPolicy;
 
@@ -261,8 +263,12 @@
 
     String getLocalAddress(String routingAddress);
 
+    TransferQueue getTransferQueue();
+
     void setFirstOpening(boolean firstOpening);
 
+    boolean makeConnection(RemoteHostAddress<?> address, final Action<Boolean> onConnectionLoss);
+
     interface Transaction
     {
         void dequeue(QueueEntry entry);
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/plugin/OutboundProtocolEngineCreator.java
similarity index 61%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/plugin/OutboundProtocolEngineCreator.java
index d2aff53..8cd11e8 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/plugin/OutboundProtocolEngineCreator.java
@@ -1,4 +1,4 @@
-/*
+package org.apache.qpid.server.plugin;/*
  *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +18,17 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
 
-public interface QueueEntryListBase extends QueueEntryList
+import org.apache.qpid.server.federation.OutboundProtocolEngine;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.VirtualHost;
+
+public interface OutboundProtocolEngineCreator extends Pluggable
 {
+    Protocol getVersion();
+    OutboundProtocolEngine newProtocolEngine(RemoteHostAddress<?> address,
+                                             VirtualHost<?> virtualHost);
+
 }
+
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java b/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
index 49e2fab..9ce9eb2 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java
@@ -72,7 +72,6 @@
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.configuration.updater.Task;
 import org.apache.qpid.server.connection.SessionPrincipal;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.FilterManager;
 import org.apache.qpid.server.filter.JMSSelectorFilter;
@@ -82,6 +81,8 @@
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.messages.QueueMessages;
 import org.apache.qpid.server.logging.subjects.QueueLogSubject;
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDeletedException;
 import org.apache.qpid.server.message.MessageInfo;
@@ -726,7 +727,7 @@
                                          final FilterManager filters,
                                          final Class<? extends ServerMessage> messageClass,
                                          final String consumerName,
-                                         final EnumSet<ConsumerImpl.Option> optionSet,
+                                         final EnumSet<ConsumerOption> optionSet,
                                          final Integer priority)
             throws ExistingExclusiveConsumer, ExistingConsumerPreventsExclusive,
                    ConsumerAccessRefused
@@ -779,7 +780,7 @@
                                                   FilterManager filters,
                                                   final Class<? extends ServerMessage> messageClass,
                                                   final String consumerName,
-                                                  EnumSet<ConsumerImpl.Option> optionSet,
+                                                  EnumSet<ConsumerOption> optionSet,
                                                   final Integer priority)
             throws ExistingExclusiveConsumer, ConsumerAccessRefused,
                    ExistingConsumerPreventsExclusive
@@ -789,6 +790,136 @@
             throw new ExistingExclusiveConsumer();
         }
 
+        if(_noLocal && !optionSet.contains(ConsumerOption.NO_LOCAL))
+        {
+            optionSet = EnumSet.copyOf(optionSet);
+            optionSet.add(ConsumerOption.NO_LOCAL);
+        }
+
+        if(_ensureNondestructiveConsumers)
+        {
+            optionSet = EnumSet.copyOf(optionSet);
+            optionSet.removeAll(EnumSet.of(ConsumerOption.SEES_REQUEUES, ConsumerOption.ACQUIRES));
+        }
+
+
+
+        boolean exclusive =  optionSet.contains(ConsumerOption.EXCLUSIVE);
+        boolean isTransient =  optionSet.contains(ConsumerOption.TRANSIENT);
+
+
+
+        if(exclusive && getConsumerCount() != 0)
+        {
+            throw new ExistingConsumerPreventsExclusive();
+        }
+
+        if(!_defaultFiltersMap.isEmpty())
+        {
+            if(filters == null)
+            {
+                filters = new FilterManager();
+            }
+            for (Map.Entry<String,Callable<MessageFilter>> filter : _defaultFiltersMap.entrySet())
+            {
+                if(!filters.hasFilter(filter.getKey()))
+                {
+                    MessageFilter f;
+                    try
+                    {
+                        f = filter.getValue().call();
+                    }
+                    catch (Exception e)
+                    {
+                        if (e instanceof RuntimeException)
+                        {
+                            throw (RuntimeException) e;
+                        }
+                        else
+                        {
+                            // Should never happen
+                            throw new ServerScopedRuntimeException(e);
+                        }
+                    }
+                    filters.add(filter.getKey(), f);
+                }
+            }
+        }
+
+
+        QueueConsumerImpl consumer = new QueueConsumerImpl(this,
+                                                           target,
+                                                           consumerName,
+                                                           filters,
+                                                           messageClass,
+                                                           optionSet,
+                                                           priority);
+
+        checkExclusivity(target);
+
+
+        consumer.open();
+
+        target.consumerAdded(consumer);
+
+
+        if (exclusive && !isTransient)
+        {
+            _exclusiveSubscriber = consumer;
+        }
+
+        if(consumer.isActive())
+        {
+            _activeSubscriberCount.incrementAndGet();
+        }
+
+        consumer.setStateListener(this);
+        QueueContext queueContext;
+        if(filters == null || !filters.startAtTail())
+        {
+            queueContext = new QueueContext(getEntries().getHead());
+        }
+        else
+        {
+            queueContext = new QueueContext(getEntries().getTail());
+        }
+        consumer.setQueueContext(queueContext);
+
+        if (!isDeleted())
+        {
+            if(consumer.isPullOnly())
+            {
+                _hasPullOnlyConsumers = true;
+            }
+            _consumerList.add(consumer);
+
+            if (isDeleted())
+            {
+                consumer.queueDeleted();
+            }
+        }
+        else
+        {
+            // TODO
+        }
+
+        childAdded(consumer);
+        consumer.addChangeListener(_deletedChildListener);
+
+        if(consumer.isPullOnly())
+        {
+            consumer.getSessionModel().getAMQPConnection().notifyWork();
+        }
+        else
+        {
+            deliverAsync();
+        }
+
+        return consumer;
+    }
+
+    private void checkExclusivity(final ConsumerTarget target) throws ConsumerAccessRefused
+    {
         Object exclusiveOwner = _exclusiveOwner;
         switch(_exclusive)
         {
@@ -858,123 +989,7 @@
             default:
                 throw new ServerScopedRuntimeException("Unknown exclusivity policy " + _exclusive);
         }
-
-        boolean exclusive =  optionSet.contains(ConsumerImpl.Option.EXCLUSIVE);
-        boolean isTransient =  optionSet.contains(ConsumerImpl.Option.TRANSIENT);
-
-        if(_noLocal && !optionSet.contains(ConsumerImpl.Option.NO_LOCAL))
-        {
-            optionSet = EnumSet.copyOf(optionSet);
-            optionSet.add(ConsumerImpl.Option.NO_LOCAL);
-        }
-
-        if(exclusive && getConsumerCount() != 0)
-        {
-            throw new ExistingConsumerPreventsExclusive();
-        }
-        if(!_defaultFiltersMap.isEmpty())
-        {
-            if(filters == null)
-            {
-                filters = new FilterManager();
-            }
-            for (Map.Entry<String,Callable<MessageFilter>> filter : _defaultFiltersMap.entrySet())
-            {
-                if(!filters.hasFilter(filter.getKey()))
-                {
-                    MessageFilter f;
-                    try
-                    {
-                        f = filter.getValue().call();
-                    }
-                    catch (Exception e)
-                    {
-                        if (e instanceof RuntimeException)
-                        {
-                            throw (RuntimeException) e;
-                        }
-                        else
-                        {
-                            // Should never happen
-                            throw new ServerScopedRuntimeException(e);
-                        }
-                    }
-                    filters.add(filter.getKey(), f);
-                }
-            }
-        }
-
-        if(_ensureNondestructiveConsumers)
-        {
-            optionSet = EnumSet.copyOf(optionSet);
-            optionSet.removeAll(EnumSet.of(ConsumerImpl.Option.SEES_REQUEUES, ConsumerImpl.Option.ACQUIRES));
-        }
-
-        QueueConsumerImpl consumer = new QueueConsumerImpl(this,
-                                                           target,
-                                                           consumerName,
-                                                           filters,
-                                                           messageClass,
-                                                           optionSet,
-                                                           priority);
-
         _exclusiveOwner = exclusiveOwner;
-        target.consumerAdded(consumer);
-
-
-        if (exclusive && !isTransient)
-        {
-            _exclusiveSubscriber = consumer;
-        }
-
-        if(consumer.isActive())
-        {
-            _activeSubscriberCount.incrementAndGet();
-        }
-
-        consumer.setStateListener(this);
-        QueueContext queueContext;
-        if(filters == null || !filters.startAtTail())
-        {
-            queueContext = new QueueContext(getEntries().getHead());
-        }
-        else
-        {
-            queueContext = new QueueContext(getEntries().getTail());
-        }
-        consumer.setQueueContext(queueContext);
-
-        if (!isDeleted())
-        {
-            if(consumer.isPullOnly())
-            {
-                _hasPullOnlyConsumers = true;
-            }
-            _consumerList.add(consumer);
-
-            if (isDeleted())
-            {
-                consumer.queueDeleted();
-            }
-        }
-        else
-        {
-            // TODO
-        }
-
-        childAdded(consumer);
-        consumer.addChangeListener(_deletedChildListener);
-
-        if(consumer.isPullOnly())
-        {
-            consumer.getSessionModel().getAMQPConnection().notifyWork();
-        }
-        else
-        {
-            deliverAsync();
-        }
-
-        return consumer;
     }
 
     @Override
@@ -1137,7 +1152,7 @@
 
     // ------ Enqueue / Dequeue
 
-    public final void enqueue(ServerMessage message, Action<? super MessageInstance> action, MessageEnqueueRecord enqueueRecord)
+    public final void enqueue(ServerMessage message, Action<? super BaseMessageInstance> action, MessageEnqueueRecord enqueueRecord)
     {
         incrementQueueCount();
         incrementQueueSize(message);
@@ -2089,6 +2104,57 @@
         txn.commit();
     }
 
+    int routeToAlternate(final QueueEntry queueEntry, final Action<? super BaseMessageInstance> action, ServerTransaction txn)
+    {
+        if (!queueEntry.isAcquired())
+        {
+            throw new IllegalStateException("Illegal queue entry state. " + this + " is not acquired.");
+        }
+
+        Exchange<?> alternateExchange = getAlternateExchange();
+        boolean autocommit =  txn == null;
+        int enqueues;
+
+        if(autocommit)
+        {
+            txn = new LocalTransaction(getVirtualHost().getMessageStore());
+        }
+
+        if (alternateExchange != null)
+        {
+            enqueues = alternateExchange.send(queueEntry.getMessage(),
+                                              queueEntry.getMessage().getInitialRoutingAddress(),
+                                              queueEntry.getInstanceProperties(),
+                                              txn,
+                                              action);
+        }
+        else
+        {
+            enqueues = 0;
+        }
+
+        txn.dequeue(queueEntry.getEnqueueRecord(), new ServerTransaction.Action()
+        {
+            public void postCommit()
+            {
+                queueEntry.delete();
+            }
+
+            public void onRollback()
+            {
+
+            }
+        });
+
+        if(autocommit)
+        {
+            txn.commit();
+        }
+
+        return enqueues;
+    }
+
+
     private void performQueueDeleteTasks()
     {
         for (Action<? super X> task : _deleteTaskList)
@@ -3095,7 +3161,7 @@
                                                                                         final String routingAddress,
                                                                                         final InstanceProperties instanceProperties,
                                                                                         final ServerTransaction txn,
-                                                                                        final Action<? super MessageInstance> postEnqueueAction)
+                                                                                        final Action<? super BaseMessageInstance> postEnqueueAction)
     {
         if (_virtualHost.getState() != State.ACTIVE)
         {
@@ -3226,7 +3292,7 @@
             case CONTAINER:
             case CONNECTION:
                 AMQSessionModel session = null;
-                for(ConsumerImpl c : getConsumers())
+                for(QueueConsumer c : getConsumers())
                 {
                     if(session == null)
                     {
@@ -3252,7 +3318,7 @@
             case CONTAINER:
             case PRINCIPAL:
                 AMQPConnection con = null;
-                for(ConsumerImpl c : getConsumers())
+                for(QueueConsumer c : getConsumers())
                 {
                     if(con == null)
                     {
@@ -3280,7 +3346,7 @@
             case NONE:
             case PRINCIPAL:
                 String containerID = null;
-                for(ConsumerImpl c : getConsumers())
+                for(QueueConsumer c : getConsumers())
                 {
                     if(containerID == null)
                     {
@@ -3311,7 +3377,7 @@
             case NONE:
             case CONTAINER:
                 Principal principal = null;
-                for(ConsumerImpl c : getConsumers())
+                for(QueueConsumer c : getConsumers())
                 {
                     if(principal == null)
                     {
@@ -3565,7 +3631,7 @@
         authorise(token, PUBLISH_ACTION, arguments);
     }
 
-    private class DeletedChildListener implements ConfigurationChangeListener
+    private class DeletedChildListener extends AbstractConfigurationChangeListener
     {
         @Override
         public void stateChanged(final ConfiguredObject object, final State oldState, final State newState)
@@ -3575,39 +3641,6 @@
                 AbstractQueue.this.childRemoved(object);
             }
         }
-
-        @Override
-        public void childAdded(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void childRemoved(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void attributeSet(final ConfiguredObject object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-
-        }
     }
 
     private static class EnqueueRequest
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java b/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java
index dc2f45a..174a77b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/BaseQueue.java
@@ -21,7 +21,7 @@
 
 package org.apache.qpid.server.queue;
 
-import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.store.TransactionLogResource;
@@ -29,7 +29,7 @@
 
 public interface BaseQueue extends TransactionLogResource
 {
-    void enqueue(ServerMessage message, Action<? super MessageInstance> action, MessageEnqueueRecord record);
+    void enqueue(ServerMessage message, Action<? super BaseMessageInstance> action, MessageEnqueueRecord record);
 
     boolean isDurable();
     boolean isDeleted();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java b/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java
index e19af3d..be951f8 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/DefinedGroupMessageGroupManager.java
@@ -20,22 +20,21 @@
  */
 package org.apache.qpid.server.queue;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.message.MessageInstance;
-import org.apache.qpid.server.message.MessageInstance.ConsumerAcquiredState;
-import org.apache.qpid.server.message.MessageInstance.EntryState;
-import org.apache.qpid.server.util.StateChangeListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.qpid.server.message.AMQMessageHeader;
-import org.apache.qpid.server.message.ServerMessage;
-
 import java.util.HashMap;
 import java.util.Map;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstance.ConsumerAcquiredState;
+import org.apache.qpid.server.message.MessageInstance.EntryState;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.util.StateChangeListener;
+
 public class DefinedGroupMessageGroupManager implements MessageGroupManager
 {
     private static final Logger _logger = LoggerFactory.getLogger(DefinedGroupMessageGroupManager.class);
@@ -183,7 +182,7 @@
             }
         }
 
-        ConsumerImpl assignedSub = group.getConsumer();
+        QueueConsumer<?> assignedSub = group.getConsumer();
 
         if(assignedSub == sub)
         {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java b/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java
index c2ad41e..98c6598 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/LastValueQueueList.java
@@ -30,7 +30,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.txn.AutoCommitTransaction;
@@ -220,7 +220,7 @@
         }
 
         @Override
-        public void release(ConsumerImpl consumer)
+        public void release(MessageInstanceConsumer consumer)
         {
             super.release(consumer);
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedBaseQueueEntryList.java b/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedBaseQueueEntryList.java
new file mode 100644
index 0000000..ad0ed0b
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedBaseQueueEntryList.java
@@ -0,0 +1,212 @@
+/*
+*
+* 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 java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+
+public abstract class OrderedBaseQueueEntryList<T extends RecoverableBaseQueue> implements QueueEntryList
+{
+
+    private final OrderedQueueEntry _head;
+
+    private volatile OrderedQueueEntry _tail;
+
+    static final AtomicReferenceFieldUpdater<OrderedBaseQueueEntryList, OrderedQueueEntry>
+            _tailUpdater =
+        AtomicReferenceFieldUpdater.newUpdater
+                (OrderedBaseQueueEntryList.class, OrderedQueueEntry.class, "_tail");
+
+
+    private final T _queue;
+
+    static final AtomicReferenceFieldUpdater<OrderedQueueEntry, OrderedQueueEntry>
+                _nextUpdater = OrderedQueueEntry._nextUpdater;
+
+    private AtomicLong _scavenges = new AtomicLong(0L);
+    private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50);
+    private final AtomicReference<QueueEntry> _unscavengedHWM = new AtomicReference<QueueEntry>();
+
+
+    public OrderedBaseQueueEntryList(T queue, HeadCreator headCreator)
+    {
+        _queue = queue;
+        _head = headCreator.createHead(this);
+        _tail = _head;
+    }
+
+    void scavenge()
+    {
+        QueueEntry hwm = _unscavengedHWM.getAndSet(null);
+        QueueEntry next = _head.getNextValidEntry();
+
+        if(hwm != null)
+        {
+            while (next != null && hwm.compareTo(next)>0)
+            {
+                next = next.getNextValidEntry();
+            }
+        }
+    }
+
+
+    public T getQueue()
+    {
+        return _queue;
+    }
+
+
+    public QueueEntry add(ServerMessage message, final MessageEnqueueRecord enqueueRecord)
+    {
+        OrderedQueueEntry node = createQueueEntry(message, enqueueRecord);
+        for (;;)
+        {
+            OrderedQueueEntry tail = _tail;
+            OrderedQueueEntry next = tail.getNextNode();
+            if (tail == _tail)
+            {
+                if (next == null)
+                {
+                    node.setEntryId(tail.getEntryId()+1);
+                    if (_nextUpdater.compareAndSet(tail, null, node))
+                    {
+                        _tailUpdater.compareAndSet(this, tail, node);
+
+                        return node;
+                    }
+                }
+                else
+                {
+                    _tailUpdater.compareAndSet(this,tail, next);
+                }
+            }
+        }
+    }
+
+    abstract protected OrderedQueueEntry createQueueEntry(ServerMessage<?> message,
+                                                          final MessageEnqueueRecord enqueueRecord);
+
+    @Override
+    public QueueEntry next(QueueEntry node)
+    {
+        return node.getNextValidEntry();
+    }
+
+    public static interface HeadCreator
+    {
+        OrderedQueueEntry createHead(QueueEntryList list);
+    }
+
+    public static class QueueEntryIteratorImpl implements QueueEntryIterator
+    {
+        private QueueEntry _lastNode;
+
+        QueueEntryIteratorImpl(QueueEntry startNode)
+        {
+            _lastNode = startNode;
+        }
+
+        public boolean atTail()
+        {
+            return _lastNode.getNextValidEntry() == null;
+        }
+
+        public QueueEntry getNode()
+        {
+            return _lastNode;
+        }
+
+        public boolean advance()
+        {
+            QueueEntry nextValidNode = _lastNode.getNextValidEntry();
+
+            if(nextValidNode != null)
+            {
+                _lastNode = nextValidNode;
+            }
+
+            return nextValidNode != null;
+        }
+    }
+
+    public QueueEntryIterator iterator()
+    {
+        return new QueueEntryIteratorImpl(_head);
+    }
+
+
+    public QueueEntry getHead()
+    {
+        return _head;
+    }
+
+    @Override
+    public QueueEntry getTail()
+    {
+        return _tail;
+    }
+
+    public void entryDeleted(QueueEntry queueEntry)
+    {
+        QueueEntry next = _head.getNextNode();
+        QueueEntry newNext = _head.getNextValidEntry();
+
+        // the head of the queue has not been deleted, hence the deletion must have been mid queue.
+        if (next == newNext)
+        {
+            QueueEntry unscavengedHWM = _unscavengedHWM.get();
+            while(unscavengedHWM == null || unscavengedHWM.compareTo(queueEntry)<0)
+            {
+                _unscavengedHWM.compareAndSet(unscavengedHWM, queueEntry);
+                unscavengedHWM = _unscavengedHWM.get();
+            }
+            if (_scavenges.incrementAndGet() > _scavengeCount)
+            {
+                _scavenges.set(0L);
+                scavenge();
+            }
+        }
+        else
+        {
+            QueueEntry unscavengedHWM = _unscavengedHWM.get();
+            if(unscavengedHWM != null && (next == null || unscavengedHWM.compareTo(next) < 0))
+            {
+                _unscavengedHWM.compareAndSet(unscavengedHWM, null);
+            }
+        }
+    }
+
+    public int getPriorities()
+    {
+        return 0;
+    }
+
+    @Override
+    public QueueEntry getOldestEntry()
+    {
+        return next(getHead());
+    }
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java b/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java
index d45dceb..9cc5496 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntry.java
@@ -34,12 +34,12 @@
 
     private volatile OrderedQueueEntry _next;
 
-    public OrderedQueueEntry(OrderedQueueEntryList queueEntryList)
+    public OrderedQueueEntry(OrderedBaseQueueEntryList queueEntryList)
     {
         super(queueEntryList);
     }
 
-    public OrderedQueueEntry(OrderedQueueEntryList queueEntryList,
+    public OrderedQueueEntry(OrderedBaseQueueEntryList queueEntryList,
                              ServerMessage message,
                              final MessageEnqueueRecord messageEnqueueRecord)
     {
@@ -63,7 +63,7 @@
             final OrderedQueueEntry newNext = next.getNextNode();
             if(newNext != null)
             {
-                OrderedQueueEntryList._nextUpdater.compareAndSet(this,next, newNext);
+                OrderedBaseQueueEntryList._nextUpdater.compareAndSet(this, next, newNext);
                 next = getNextNode();
             }
             else
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java b/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java
index 1283530..9fb3321 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/OrderedQueueEntryList.java
@@ -1,213 +1,80 @@
 /*
-*
-* 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.
-*
-*/
+ *
+ * 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 java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
-
-import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
+import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.Queue;
-import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.txn.LocalTransaction;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.Action;
 
-public abstract class OrderedQueueEntryList implements QueueEntryList
+public abstract class OrderedQueueEntryList extends OrderedBaseQueueEntryList<AbstractQueue<?>>
 {
-
-    private final OrderedQueueEntry _head;
-
-    private volatile OrderedQueueEntry _tail;
-
-    static final AtomicReferenceFieldUpdater<OrderedQueueEntryList, OrderedQueueEntry>
-            _tailUpdater =
-        AtomicReferenceFieldUpdater.newUpdater
-        (OrderedQueueEntryList.class, OrderedQueueEntry.class, "_tail");
-
-
-    private final Queue<?> _queue;
-
-    static final AtomicReferenceFieldUpdater<OrderedQueueEntry, OrderedQueueEntry>
-                _nextUpdater = OrderedQueueEntry._nextUpdater;
-
-    private AtomicLong _scavenges = new AtomicLong(0L);
-    private final long _scavengeCount = Integer.getInteger("qpid.queue.scavenge_count", 50);
-    private final AtomicReference<QueueEntry> _unscavengedHWM = new AtomicReference<QueueEntry>();
-
-
-    public OrderedQueueEntryList(Queue<?> queue, HeadCreator headCreator)
+    public OrderedQueueEntryList(final AbstractQueue<?> queue,
+                                 final HeadCreator headCreator)
     {
-        _queue = queue;
-        _head = headCreator.createHead(this);
-        _tail = _head;
-    }
-
-    void scavenge()
-    {
-        QueueEntry hwm = _unscavengedHWM.getAndSet(null);
-        QueueEntry next = _head.getNextValidEntry();
-
-        if(hwm != null)
-        {
-            while (next != null && hwm.compareTo(next)>0)
-            {
-                next = next.getNextValidEntry();
-            }
-        }
-    }
-
-
-    public Queue<?> getQueue()
-    {
-        return _queue;
-    }
-
-
-    public QueueEntry add(ServerMessage message, final MessageEnqueueRecord enqueueRecord)
-    {
-        OrderedQueueEntry node = createQueueEntry(message, enqueueRecord);
-        for (;;)
-        {
-            OrderedQueueEntry tail = _tail;
-            OrderedQueueEntry next = tail.getNextNode();
-            if (tail == _tail)
-            {
-                if (next == null)
-                {
-                    node.setEntryId(tail.getEntryId()+1);
-                    if (_nextUpdater.compareAndSet(tail, null, node))
-                    {
-                        _tailUpdater.compareAndSet(this, tail, node);
-
-                        return node;
-                    }
-                }
-                else
-                {
-                    _tailUpdater.compareAndSet(this,tail, next);
-                }
-            }
-        }
-    }
-
-    abstract protected OrderedQueueEntry createQueueEntry(ServerMessage<?> message,
-                                                          final MessageEnqueueRecord enqueueRecord);
-
-    @Override
-    public QueueEntry next(QueueEntry node)
-    {
-        return node.getNextValidEntry();
-    }
-
-    public static interface HeadCreator
-    {
-        OrderedQueueEntry createHead(QueueEntryList list);
-    }
-
-    public static class QueueEntryIteratorImpl implements QueueEntryIterator
-    {
-        private QueueEntry _lastNode;
-
-        QueueEntryIteratorImpl(QueueEntry startNode)
-        {
-            _lastNode = startNode;
-        }
-
-        public boolean atTail()
-        {
-            return _lastNode.getNextValidEntry() == null;
-        }
-
-        public QueueEntry getNode()
-        {
-            return _lastNode;
-        }
-
-        public boolean advance()
-        {
-            QueueEntry nextValidNode = _lastNode.getNextValidEntry();
-
-            if(nextValidNode != null)
-            {
-                _lastNode = nextValidNode;
-            }
-
-            return nextValidNode != null;
-        }
-    }
-
-    public QueueEntryIterator iterator()
-    {
-        return new QueueEntryIteratorImpl(_head);
-    }
-
-
-    public QueueEntry getHead()
-    {
-        return _head;
+        super(queue, headCreator);
     }
 
     @Override
-    public QueueEntry getTail()
+    public void onAcquiredByConsumer(final QueueEntry queueEntry, final MessageInstanceConsumer consumer)
     {
-        return _tail;
-    }
-
-    public void entryDeleted(QueueEntry queueEntry)
-    {
-        QueueEntry next = _head.getNextNode();
-        QueueEntry newNext = _head.getNextValidEntry();
-
-        // the head of the queue has not been deleted, hence the deletion must have been mid queue.
-        if (next == newNext)
-        {
-            QueueEntry unscavengedHWM = _unscavengedHWM.get();
-            while(unscavengedHWM == null || unscavengedHWM.compareTo(queueEntry)<0)
-            {
-                _unscavengedHWM.compareAndSet(unscavengedHWM, queueEntry);
-                unscavengedHWM = _unscavengedHWM.get();
-            }
-            if (_scavenges.incrementAndGet() > _scavengeCount)
-            {
-                _scavenges.set(0L);
-                scavenge();
-            }
-        }
-        else
-        {
-            QueueEntry unscavengedHWM = _unscavengedHWM.get();
-            if(unscavengedHWM != null && (next == null || unscavengedHWM.compareTo(next) < 0))
-            {
-                _unscavengedHWM.compareAndSet(unscavengedHWM, null);
-            }
-        }
-    }
-
-    public int getPriorities()
-    {
-        return 0;
+        getQueue().incrementUnackedMsgCount(queueEntry);
     }
 
     @Override
-    public QueueEntry getOldestEntry()
+    public void onNoLongerAcquiredByConsumer(final QueueEntry queueEntry)
     {
-        return next(getHead());
+        getQueue().decrementUnackedMsgCount(queueEntry);
     }
 
+    @Override
+    public void requeue(final QueueEntry queueEntry)
+    {
+        getQueue().requeue(queueEntry);
+    }
+
+    @Override
+    public boolean isHeld(final QueueEntry queueEntry, final long evaluationTime)
+    {
+        return getQueue().isHeld(queueEntry, evaluationTime);
+    }
+
+    @Override
+    public void dequeue(final QueueEntry queueEntry)
+    {
+        getQueue().dequeue(queueEntry);
+    }
+
+    @Override
+    public int routeToAlternate(final QueueEntry queueEntry, final Action<? super BaseMessageInstance> action, ServerTransaction txn)
+    {
+        return getQueue().routeToAlternate(queueEntry, action, txn);
+    }
+
+    @Override
+    public int getMaximumDeliveryAttempts()
+    {
+        return getQueue().getMaximumDeliveryAttempts();
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
index 771097a..d8d959e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumer.java
@@ -20,11 +20,13 @@
  */
 package org.apache.qpid.server.queue;
 
+import org.apache.qpid.server.consumer.ConsumerTarget;
+import org.apache.qpid.server.message.AcquiringMessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.model.Consumer;
 import org.apache.qpid.server.model.Queue;
 
-public interface QueueConsumer<X extends QueueConsumer<X>> extends Consumer<X>
+public interface QueueConsumer<X extends QueueConsumer<X>> extends Consumer<X>, AcquiringMessageInstanceConsumer<X, ConsumerTarget>
 {
     void flushBatched();
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java
index 804bde1..d13f1a3 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueConsumerImpl.java
@@ -46,9 +46,9 @@
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.messages.SubscriptionMessages;
 import org.apache.qpid.server.logging.subjects.QueueLogSubject;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageReference;
-import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.AbstractConfiguredObject;
 import org.apache.qpid.server.model.Consumer;
@@ -124,7 +124,7 @@
                       final String consumerName,
                       final FilterManager filters,
                       final Class<? extends ServerMessage> messageClass,
-                      EnumSet<Option> optionSet,
+                      EnumSet<ConsumerOption> optionSet,
                       final Integer priority)
     {
         super(parentsMap(queue, target.getSessionModel().getModelObject()),
@@ -133,18 +133,16 @@
         _sessionReference = target.getSessionModel().getConnectionReference();
         _consumerNumber = CONSUMER_NUMBER_GENERATOR.getAndIncrement();
         _filters = filters;
-        _acquires = optionSet.contains(Option.ACQUIRES);
-        _seesRequeues = optionSet.contains(Option.SEES_REQUEUES);
-        _isTransient = optionSet.contains(Option.TRANSIENT);
+        _acquires = optionSet.contains(ConsumerOption.ACQUIRES);
+        _seesRequeues = optionSet.contains(ConsumerOption.SEES_REQUEUES);
+        _isTransient = optionSet.contains(ConsumerOption.TRANSIENT);
         _target = target;
         _queue = queue;
 
         // Access control
         authorise(Operation.CREATE);
 
-        open();
 
-        setupLogging();
 
         _listener = new StateChangeListener<ConsumerTarget, ConsumerTarget.State>()
         {
@@ -168,20 +166,29 @@
                             getEventLogger().message(getLogSubject(), SubscriptionMessages.STATE(period));
                         }
                     };
+
+
+    }
+
+    @Override
+    protected void onOpen()
+    {
+        super.onOpen();
+        setupLogging();
     }
 
     private static Map<String, Object> createAttributeMap(String name,
                                                           FilterManager filters,
-                                                          EnumSet<Option> optionSet,
+                                                          EnumSet<ConsumerOption> optionSet,
                                                           Integer priority)
     {
         Map<String,Object> attributes = new HashMap<String, Object>();
         attributes.put(ID, UUID.randomUUID());
         attributes.put(NAME, name);
-        attributes.put(EXCLUSIVE, optionSet.contains(Option.EXCLUSIVE));
-        attributes.put(NO_LOCAL, optionSet.contains(Option.NO_LOCAL));
-        attributes.put(DISTRIBUTION_MODE, optionSet.contains(Option.ACQUIRES) ? "MOVE" : "COPY");
-        attributes.put(DURABLE,optionSet.contains(Option.DURABLE));
+        attributes.put(EXCLUSIVE, optionSet.contains(ConsumerOption.EXCLUSIVE));
+        attributes.put(NO_LOCAL, optionSet.contains(ConsumerOption.NO_LOCAL));
+        attributes.put(DISTRIBUTION_MODE, optionSet.contains(ConsumerOption.ACQUIRES) ? "MOVE" : "COPY");
+        attributes.put(DURABLE,optionSet.contains(ConsumerOption.DURABLE));
         attributes.put(LIFETIME_POLICY, LifetimePolicy.DELETE_ON_SESSION_END);
         if(priority != null)
         {
@@ -297,9 +304,9 @@
     }
 
     @Override
-    public MessageSource getMessageSource()
+    public Object getIdentifier()
     {
-        return _queue;
+        return getConsumerNumber();
     }
 
     @Override
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
index b723f05..8270e34 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntry.java
@@ -20,20 +20,20 @@
 */
 package org.apache.qpid.server.queue;
 
+import org.apache.qpid.server.message.AcquiringMessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageReference;
-import org.apache.qpid.server.model.Queue;
 
 public interface QueueEntry extends MessageInstance, Comparable<QueueEntry>
 {
 
-    Queue<?> getQueue();
+    RecoverableBaseQueue getQueue();
 
     long getSize();
 
     boolean acquireOrSteal(final Runnable delayedAcquisitionTask);
 
-    QueueConsumer getDeliveredConsumer();
+    AcquiringMessageInstanceConsumer<?,?> getDeliveredConsumer();
 
     boolean isQueueDeleted();
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
index a658a21..aeb84ef 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryImpl.java
@@ -30,15 +30,16 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.filter.Filterable;
+import org.apache.qpid.server.message.AcquiringMessageInstanceConsumer;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDeletedException;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.Exchange;
-import org.apache.qpid.server.model.Queue;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.server.txn.LocalTransaction;
@@ -55,7 +56,7 @@
 
     private final MessageReference _message;
 
-    private Set<Long> _rejectedBy = null;
+    private Set<Object> _rejectedBy = null;
 
     private static final EntryState HELD_STATE = new EntryState()
     {
@@ -177,7 +178,7 @@
         return _entryId;
     }
 
-    public Queue<?> getQueue()
+    public RecoverableBaseQueue getQueue()
     {
         return _queueEntryList.getQueue();
     }
@@ -263,7 +264,7 @@
         boolean acquired = acquire();
         if(!acquired)
         {
-            QueueConsumer consumer = getDeliveredConsumer();
+            AcquiringMessageInstanceConsumer<?,?> consumer = getDeliveredConsumer();
             acquired = removeAcquisitionFromConsumer(consumer);
             if(acquired)
             {
@@ -304,19 +305,19 @@
         return acquired;
     }
 
-    public boolean acquire(ConsumerImpl sub)
+    public boolean acquire(MessageInstanceConsumer sub)
     {
-        final boolean acquired = acquire(((QueueConsumer<?>) sub).getOwningState().getUnstealableState());
+        final boolean acquired = acquire(((AcquiringMessageInstanceConsumer<?,?>) sub).getOwningState().getUnstealableState());
         if(acquired)
         {
             _deliveryCountUpdater.compareAndSet(this,-1,0);
-            getQueue().incrementUnackedMsgCount(this);
+            _queueEntryList.onAcquiredByConsumer(this, sub);
         }
         return acquired;
     }
 
     @Override
-    public boolean makeAcquisitionUnstealable(final ConsumerImpl consumer)
+    public boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer)
     {
         EntryState state = _state;
         if(state instanceof StealableConsumerAcquiredState
@@ -357,9 +358,9 @@
     }
 
     @Override
-    public ConsumerImpl getAcquiringConsumer()
+    public MessageInstanceConsumer getAcquiringConsumer()
     {
-        ConsumerImpl consumer;
+        AcquiringMessageInstanceConsumer<?,?> consumer;
         EntryState state = _state;
         if (state instanceof ConsumerAcquiredState)
         {
@@ -373,14 +374,14 @@
     }
 
     @Override
-    public boolean isAcquiredBy(ConsumerImpl consumer)
+    public boolean isAcquiredBy(MessageInstanceConsumer consumer)
     {
         EntryState state = _state;
         return (state instanceof ConsumerAcquiredState && ((ConsumerAcquiredState)state).getConsumer() == consumer);
     }
 
     @Override
-    public boolean removeAcquisitionFromConsumer(ConsumerImpl consumer)
+    public boolean removeAcquisitionFromConsumer(MessageInstanceConsumer consumer)
     {
         EntryState state = _state;
         if(state instanceof StealableConsumerAcquiredState
@@ -411,7 +412,7 @@
     }
 
     @Override
-    public void release(ConsumerImpl consumer)
+    public void release(MessageInstanceConsumer consumer)
     {
         EntryState state = _state;
         if(isAcquiredBy(consumer) && _stateUpdater.compareAndSet(this, state, AVAILABLE_STATE))
@@ -424,12 +425,12 @@
     {
         if (previousState instanceof ConsumerAcquiredState)
         {
-            getQueue().decrementUnackedMsgCount(this);
+            _queueEntryList.onNoLongerAcquiredByConsumer(this);
         }
 
         if(!getQueue().isDeleted())
         {
-            getQueue().requeue(this);
+            _queueEntryList.requeue(this);
             if (_stateChangeListeners != null && previousState.getState() == State.ACQUIRED)
             {
                 notifyStateChange(previousState, AVAILABLE_STATE);
@@ -448,7 +449,7 @@
         EntryState state;
         while((state = _state).getState() == State.AVAILABLE)
         {
-            boolean isHeld = getQueue().isHeld(this, evaluationTime);
+            boolean isHeld = _queueEntryList.isHeld(this, evaluationTime);
             if(state == AVAILABLE_STATE && isHeld)
             {
                 if(!_stateUpdater.compareAndSet(this, state, HELD_STATE))
@@ -475,20 +476,20 @@
     }
 
     @Override
-    public QueueConsumer getDeliveredConsumer()
+    public AcquiringMessageInstanceConsumer getDeliveredConsumer()
     {
-        return (QueueConsumer) getAcquiringConsumer();
+        return (AcquiringMessageInstanceConsumer) getAcquiringConsumer();
     }
 
     public void reject()
     {
-        QueueConsumer consumer = getDeliveredConsumer();
+        AcquiringMessageInstanceConsumer<?,?> consumer = getDeliveredConsumer();
 
         if (consumer != null)
         {
             if (_rejectedBy == null)
             {
-                _rejectedBy = new HashSet<Long>();
+                _rejectedBy = new HashSet<>();
             }
 
             _rejectedBy.add(consumer.getConsumerNumber());
@@ -499,12 +500,12 @@
         }
     }
 
-    public boolean isRejectedBy(ConsumerImpl consumer)
+    public boolean isRejectedBy(MessageInstanceConsumer consumer)
     {
 
         if (_rejectedBy != null) // We have consumers that rejected this message
         {
-            return _rejectedBy.contains(consumer.getConsumerNumber());
+            return _rejectedBy.contains(consumer.getIdentifier());
         }
         else // This message hasn't been rejected yet.
         {
@@ -525,10 +526,10 @@
         {
             if (state instanceof ConsumerAcquiredState)
             {
-                getQueue().decrementUnackedMsgCount(this);
+                _queueEntryList.onNoLongerAcquiredByConsumer(this);
             }
 
-            getQueue().dequeue(this);
+            _queueEntryList.dequeue(this);
             if(_stateChangeListeners != null)
             {
                 notifyStateChange(state, DEQUEUED_STATE);
@@ -582,55 +583,10 @@
         }
     }
 
-    public int routeToAlternate(final Action<? super MessageInstance> action, ServerTransaction txn)
+    public int routeToAlternate(final Action<? super BaseMessageInstance> action, ServerTransaction txn)
     {
-        if (!isAcquired())
-        {
-            throw new IllegalStateException("Illegal queue entry state. " + this + " is not acquired.");
-        }
+        return _queueEntryList.routeToAlternate(this, action, txn);
 
-        final Queue<?> currentQueue = getQueue();
-        Exchange<?> alternateExchange = currentQueue.getAlternateExchange();
-        boolean autocommit =  txn == null;
-        int enqueues;
-
-        if(autocommit)
-        {
-            txn = new LocalTransaction(getQueue().getVirtualHost().getMessageStore());
-        }
-
-        if (alternateExchange != null)
-        {
-            enqueues = alternateExchange.send(getMessage(),
-                                              getMessage().getInitialRoutingAddress(),
-                                              getInstanceProperties(),
-                                              txn,
-                                              action);
-        }
-        else
-        {
-            enqueues = 0;
-        }
-
-        txn.dequeue(getEnqueueRecord(), new ServerTransaction.Action()
-        {
-            public void postCommit()
-            {
-                delete();
-            }
-
-            public void onRollback()
-            {
-
-            }
-        });
-
-        if(autocommit)
-        {
-            txn.commit();
-        }
-
-        return enqueues;
     }
 
     public boolean isQueueDeleted()
@@ -692,7 +648,7 @@
     @Override
     public int getMaximumDeliveryCount()
     {
-        return getQueue().getMaximumDeliveryAttempts();
+        return _queueEntryList.getMaximumDeliveryAttempts();
     }
 
     public void incrementDeliveryCount()
@@ -723,7 +679,7 @@
     @Override
     public boolean resend()
     {
-        QueueConsumer sub = getDeliveredConsumer();
+        AcquiringMessageInstanceConsumer<?,?> sub = getDeliveredConsumer();
         if(sub != null)
         {
             return sub.resend(this);
@@ -734,7 +690,7 @@
     @Override
     public TransactionLogResource getOwningResource()
     {
-        return getQueue();
+        return _queueEntryList.getQueue();
     }
 
     public void setRedelivered()
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
index c97e58b..37e0868 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryList.java
@@ -20,13 +20,16 @@
 */
 package org.apache.qpid.server.queue;
 
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.server.model.Queue;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.Action;
 
 public interface QueueEntryList
 {
-    Queue<?> getQueue();
+    RecoverableBaseQueue getQueue();
 
     QueueEntry add(ServerMessage message, final MessageEnqueueRecord enqueueRecord);
 
@@ -44,4 +47,17 @@
     
     int getPriorities();
 
+    void onAcquiredByConsumer(QueueEntry queueEntry, final MessageInstanceConsumer consumer);
+
+    void onNoLongerAcquiredByConsumer(QueueEntry queueEntry);
+
+    void requeue(QueueEntry queueEntry);
+
+    boolean isHeld(QueueEntry queueEntry, long evaluationTime);
+
+    void dequeue(QueueEntry queueEntry);
+
+    int routeToAlternate(QueueEntry queueEntry, Action<? super BaseMessageInstance> action, ServerTransaction txn);
+
+    int getMaximumDeliveryAttempts();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/queue/RecoverableBaseQueue.java
similarity index 70%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/queue/RecoverableBaseQueue.java
index d2aff53..53a9e67 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/RecoverableBaseQueue.java
@@ -20,6 +20,15 @@
  */
 package org.apache.qpid.server.queue;
 
-public interface QueueEntryListBase extends QueueEntryList
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+
+public interface RecoverableBaseQueue extends BaseQueue
 {
+    void recover(ServerMessage<?> message, MessageEnqueueRecord record);
+
+    void completeRecovery();
+
+    VirtualHost<?> getVirtualHost();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java b/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
index 0c8f541..4a1e81d 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/queue/SortedQueueEntryList.java
@@ -20,9 +20,13 @@
  */
 package org.apache.qpid.server.queue;
 
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.queue.SortedQueueEntry.Colour;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.Action;
 
 /**
  * A sorted implementation of QueueEntryList.
@@ -52,6 +56,50 @@
         return _queue;
     }
 
+
+    @Override
+    public void onAcquiredByConsumer(final QueueEntry queueEntry, final MessageInstanceConsumer consumer)
+    {
+        getQueue().incrementUnackedMsgCount(queueEntry);
+    }
+
+    @Override
+    public void onNoLongerAcquiredByConsumer(final QueueEntry queueEntry)
+    {
+        getQueue().decrementUnackedMsgCount(queueEntry);
+    }
+
+    @Override
+    public void requeue(final QueueEntry queueEntry)
+    {
+        getQueue().requeue(queueEntry);
+    }
+
+    @Override
+    public boolean isHeld(final QueueEntry queueEntry, final long evaluationTime)
+    {
+        return getQueue().isHeld(queueEntry, evaluationTime);
+    }
+
+    @Override
+    public void dequeue(final QueueEntry queueEntry)
+    {
+        getQueue().dequeue(queueEntry);
+    }
+
+    @Override
+    public int routeToAlternate(final QueueEntry queueEntry, final Action<? super BaseMessageInstance> action, ServerTransaction txn)
+    {
+        return getQueue().routeToAlternate(queueEntry, action, txn);
+    }
+
+    @Override
+    public int getMaximumDeliveryAttempts()
+    {
+        return getQueue().getMaximumDeliveryAttempts();
+    }
+
+
     public SortedQueueEntry add(final ServerMessage message, final MessageEnqueueRecord enqueueRecord)
     {
         synchronized(_lock)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java b/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java
index bff091f..9a952e3 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java
@@ -37,9 +37,9 @@
 
 import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.messages.KeyStoreMessages;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.AbstractConfiguredObject;
 import org.apache.qpid.server.model.Broker;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.IntegrityViolationException;
 import org.apache.qpid.server.model.KeyStore;
@@ -115,7 +115,7 @@
         else
         {
             final int frequency = checkFrequency;
-            getBroker().addChangeListener(new ConfigurationChangeListener()
+            getBroker().addChangeListener(new AbstractConfigurationChangeListener()
             {
                 @Override
                 public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
@@ -135,38 +135,6 @@
                     }
                 }
 
-                @Override
-                public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
-                {
-
-                }
-
-                @Override
-                public void childRemoved(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
-                {
-
-                }
-
-                @Override
-                public void attributeSet(final ConfiguredObject<?> object,
-                                         final String attributeName,
-                                         final Object oldAttributeValue,
-                                         final Object newAttributeValue)
-                {
-
-                }
-
-                @Override
-                public void bulkChangeStart(final ConfiguredObject<?> object)
-                {
-
-                }
-
-                @Override
-                public void bulkChangeEnd(final ConfiguredObject<?> object)
-                {
-
-                }
             });
         }
     }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSource.java b/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSource.java
index 82f3702..3da95f6 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSource.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSource.java
@@ -35,21 +35,20 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.FilterManager;
-import org.apache.qpid.server.message.MessageSource;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.message.internal.InternalMessage;
 import org.apache.qpid.server.message.internal.InternalMessageHeader;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.TrustStore;
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.virtualhost.AbstractSystemMessageSource;
 
-public class TrustStoreMessageSource extends AbstractSystemMessageSource implements MessageSource
+public class TrustStoreMessageSource extends AbstractSystemMessageSource
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(TrustStoreMessageSource.class);
 
@@ -63,7 +62,7 @@
         super(getSourceNameFromTrustStore(trustStore), virtualHost);
         _virtualHost = virtualHost;
         _trustStore = trustStore;
-        _trustStore.addChangeListener(new ConfigurationChangeListener()
+        _trustStore.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
@@ -75,18 +74,6 @@
             }
 
             @Override
-            public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
-            {
-
-            }
-
-            @Override
-            public void childRemoved(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
-            {
-
-            }
-
-            @Override
             public void attributeSet(final ConfiguredObject<?> object,
                                      final String attributeName,
                                      final Object oldAttributeValue,
@@ -95,17 +82,7 @@
                 updateCertCache();
             }
 
-            @Override
-            public void bulkChangeStart(final ConfiguredObject<?> object)
-            {
 
-            }
-
-            @Override
-            public void bulkChangeEnd(final ConfiguredObject<?> object)
-            {
-
-            }
         });
         if(_trustStore.getState() == State.ACTIVE)
         {
@@ -114,15 +91,16 @@
     }
 
     @Override
-    public Consumer addConsumer(final ConsumerTarget target,
-                                final FilterManager filters,
-                                final Class<? extends ServerMessage> messageClass,
-                                final String consumerName,
-                                final EnumSet<ConsumerImpl.Option> options, final Integer priority)
+    public SystemMessageSourceConsumer addConsumer(final ConsumerTarget target,
+                                                   final FilterManager filters,
+                                                   final Class<? extends ServerMessage> messageClass,
+                                                   final String consumerName,
+                                                   final EnumSet<ConsumerOption> options, final Integer priority)
             throws ExistingExclusiveConsumer, ExistingConsumerPreventsExclusive,
                    ConsumerAccessRefused
     {
-        final Consumer consumer = super.addConsumer(target, filters, messageClass, consumerName, options, priority);
+        final SystemMessageSourceConsumer
+                consumer = super.addConsumer(target, filters, messageClass, consumerName, options, priority);
         consumer.send(createMessage());
         target.queueEmpty();
         return consumer;
@@ -141,7 +119,7 @@
     {
         InternalMessage message = createMessage();
 
-        for(Consumer c : new ArrayList<>(getConsumers()))
+        for(SystemMessageSourceConsumer c : new ArrayList<>(getConsumers()))
         {
             c.send(message);
         }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSourceCreator.java b/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSourceCreator.java
index c81d19e..d05f9cd 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSourceCreator.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/TrustStoreMessageSourceCreator.java
@@ -22,8 +22,8 @@
 
 import java.util.Collection;
 
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.Broker;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.TrustStore;
@@ -58,12 +58,8 @@
             updateTrustStoreSourceRegistration(registry, trustStore);
             trustStore.addChangeListener(trustStoreChangeListener);
         }
-        broker.addChangeListener(new ConfigurationChangeListener()
+        broker.addChangeListener(new AbstractConfigurationChangeListener()
         {
-            @Override
-            public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
-            {
-            }
 
             @Override
             public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
@@ -90,26 +86,6 @@
                 }
             }
 
-            @Override
-            public void attributeSet(final ConfiguredObject<?> object,
-                                     final String attributeName,
-                                     final Object oldAttributeValue,
-                                     final Object newAttributeValue)
-            {
-
-            }
-
-            @Override
-            public void bulkChangeStart(final ConfiguredObject<?> object)
-            {
-
-            }
-
-            @Override
-            public void bulkChangeEnd(final ConfiguredObject<?> object)
-            {
-
-            }
         });
     }
 
@@ -141,7 +117,7 @@
         }
     }
 
-    private class TrustStoreChangeListener implements ConfigurationChangeListener
+    private class TrustStoreChangeListener extends AbstractConfigurationChangeListener
     {
 
         private final SystemNodeRegistry _registry;
@@ -159,19 +135,6 @@
             updateTrustStoreSourceRegistration(_registry, (TrustStore<?>)object);
         }
 
-
-        @Override
-        public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
-        {
-
-        }
-
-        @Override
-        public void childRemoved(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
-        {
-
-        }
-
         @Override
         public void attributeSet(final ConfiguredObject<?> object,
                                  final String attributeName,
@@ -181,16 +144,5 @@
             updateTrustStoreSourceRegistration(_registry, (TrustStore<?>)object);
         }
 
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-
-        }
     }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java b/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java
index d5cd49d..e596ab9 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/store/VirtualHostStoreUpgraderAndRecoverer.java
@@ -36,13 +36,12 @@
 import org.apache.qpid.server.configuration.IllegalConfigurationException;
 import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener;
 import org.apache.qpid.server.filter.FilterSupport;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.AbstractConfiguredObject;
 import org.apache.qpid.server.model.Binding;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.Queue;
-import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.UUIDGenerator;
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.model.VirtualHostNode;
@@ -627,13 +626,8 @@
                 }
             });
         }
-        _virtualHostNode.addChangeListener(new ConfigurationChangeListener()
+        _virtualHostNode.addChangeListener(new AbstractConfigurationChangeListener()
         {
-            @Override
-            public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
-            {
-
-            }
 
             @Override
             public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
@@ -665,26 +659,6 @@
                 }
             }
 
-            @Override
-            public void attributeSet(final ConfiguredObject<?> object,
-                                     final String attributeName,
-                                     final Object oldAttributeValue,
-                                     final Object newAttributeValue)
-            {
-
-            }
-
-            @Override
-            public void bulkChangeStart(final ConfiguredObject<?> object)
-            {
-
-            }
-
-            @Override
-            public void bulkChangeEnd(final ConfiguredObject<?> object)
-            {
-
-            }
         });
         if(isNew)
         {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transfer/OutboundTransferDestination.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/OutboundTransferDestination.java
new file mode 100644
index 0000000..96e5918
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/OutboundTransferDestination.java
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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.transfer;
+
+import java.security.AccessControlException;
+import java.util.Map;
+
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.InstanceProperties;
+import org.apache.qpid.server.message.MessageDestination;
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.NamedAddressSpace;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.security.SecurityToken;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.store.StorableMessageMetaData;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.Action;
+import org.apache.qpid.server.virtualhost.VirtualHostUnavailableException;
+
+public class OutboundTransferDestination implements MessageDestination
+{
+    private final VirtualHost<?> _virtualHost;
+    private final String _address;
+
+    public OutboundTransferDestination(final VirtualHost<?> virtualHost, final String address)
+    {
+        _virtualHost = virtualHost;
+        _address = address;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "$transfer";
+    }
+
+    @Override
+    public NamedAddressSpace getAddressSpace()
+    {
+        return _virtualHost;
+    }
+
+    @Override
+    public void authorisePublish(final SecurityToken token, final Map<String, Object> arguments)
+            throws AccessControlException
+    {
+
+    }
+
+    @Override
+    public <M extends ServerMessage<? extends StorableMessageMetaData>> int send(final M message,
+                                                                                 final String routingAddress,
+                                                                                 final InstanceProperties instanceProperties,
+                                                                                 final ServerTransaction txn,
+                                                                                 final Action<? super BaseMessageInstance> postEnqueueAction)
+    {
+        if (_virtualHost.getState() != State.ACTIVE)
+        {
+            throw new VirtualHostUnavailableException(this._virtualHost);
+        }
+
+
+        final TransferQueue transferQueue = _virtualHost.getTransferQueue();
+        txn.enqueue(transferQueue, message, new ServerTransaction.EnqueueAction()
+        {
+            MessageReference _reference = message.newReference();
+
+            public void postCommit(MessageEnqueueRecord... records)
+            {
+                try
+                {
+                    for (final MessageEnqueueRecord record : records)
+                    {
+                        transferQueue.enqueue(message, postEnqueueAction, record);
+                    }
+                }
+                finally
+                {
+                    _reference.release();
+                }
+            }
+
+            public void onRollback()
+            {
+                _reference.release();
+            }
+        });
+        return 1;
+
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transfer/QueueContext.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/QueueContext.java
new file mode 100755
index 0000000..183b4e3
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/QueueContext.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * 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.transfer;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+import org.apache.qpid.server.queue.QueueEntry;
+
+final class QueueContext
+{
+    private volatile QueueEntry _lastSeenEntry;
+    private volatile QueueEntry _releasedEntry;
+
+    static final AtomicReferenceFieldUpdater<QueueContext, QueueEntry>
+            _lastSeenUpdater =
+        AtomicReferenceFieldUpdater.newUpdater
+                (QueueContext.class, QueueEntry.class, "_lastSeenEntry");
+    static final AtomicReferenceFieldUpdater<QueueContext, QueueEntry>
+            _releasedUpdater =
+        AtomicReferenceFieldUpdater.newUpdater
+                (QueueContext.class, QueueEntry.class, "_releasedEntry");
+
+    public QueueContext(QueueEntry head)
+    {
+        _lastSeenEntry = head;
+    }
+
+    public QueueEntry getLastSeenEntry()
+    {
+        return _lastSeenEntry;
+    }
+
+
+    QueueEntry getReleasedEntry()
+    {
+        return _releasedEntry;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "QueueContext{" +
+               "_lastSeenEntry=" + _lastSeenEntry +
+               ", _releasedEntry=" + _releasedEntry +
+               '}';
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueue.java
similarity index 69%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueue.java
index d2aff53..cce739b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueue.java
@@ -18,8 +18,13 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.transfer;
 
-public interface QueueEntryListBase extends QueueEntryList
+import org.apache.qpid.server.message.MessageDestination;
+import org.apache.qpid.server.queue.RecoverableBaseQueue;
+
+public interface TransferQueue extends RecoverableBaseQueue, MessageDestination
 {
+    TransferQueueConsumer addConsumer(TransferTarget target,
+                                      String consumerName);
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueConsumer.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueConsumer.java
new file mode 100644
index 0000000..0547fee
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueConsumer.java
@@ -0,0 +1,225 @@
+/*
+ *
+ * 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.transfer;
+
+import java.util.Collection;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.regex.Pattern;
+
+import org.apache.qpid.server.message.AcquiringMessageInstanceConsumer;
+import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.queue.QueueEntry;
+
+public class TransferQueueConsumer implements AcquiringMessageInstanceConsumer<TransferQueueConsumer, TransferTarget>
+{
+    private final TransferQueueImpl _transferQueue;
+    private final TransferTarget _target;
+    private final String _name;
+
+    private final ConcurrentLinkedQueue<TransferQueueEntry> _entries = new ConcurrentLinkedQueue<>();
+    private final Pattern _matchPattern;
+    private volatile QueueContext _queueContext;
+
+
+    private final MessageInstance.StealableConsumerAcquiredState<TransferQueueConsumer>
+            _owningState = new MessageInstance.StealableConsumerAcquiredState<>(this);
+    private final Object _identifier = new Object();
+
+
+    TransferQueueConsumer(final TransferQueueImpl transferQueue,
+                          final TransferTarget target,
+                          final String consumerName)
+    {
+        _transferQueue = transferQueue;
+        _target = target;
+        _name = consumerName;
+
+        Collection<String> globalAddressDomains = _target.getGlobalAddressDomains();
+        StringBuilder matchPattern = new StringBuilder();
+        boolean isFirst = true;
+        for(String domain : globalAddressDomains)
+        {
+            if(isFirst)
+            {
+                isFirst = false;
+            }
+            else
+            {
+                matchPattern.append('|');
+            }
+            matchPattern.append('(');
+            matchPattern.append(Pattern.quote(domain.endsWith("/") ? domain : (domain + "/")));
+            matchPattern.append(".*)");
+        }
+        _matchPattern = Pattern.compile(matchPattern.toString());
+    }
+
+    boolean hasInterest(final QueueEntry entry)
+    {
+        String initialRoutingAddress = entry.getMessage().getInitialRoutingAddress();
+        boolean matches = _matchPattern.matcher(initialRoutingAddress).matches();
+        return matches;
+    }
+
+    public boolean processPending()
+    {
+        if(!isSuspended())
+        {
+            TransferQueueEntry entry = _transferQueue.getNextAvailableEntry(this);
+            if(entry != null && !wouldSuspend(entry))
+            {
+                if (!entry.acquire(this))
+                {
+                    // restore credit here that would have been taken away by wouldSuspend since we didn't manage
+                    // to acquire the entry for this consumer
+                    restoreCredit(entry);
+                }
+                else
+                {
+                    _transferQueue.setLastSeenEntry(this, entry);
+
+                    send(entry);
+                    return true;
+                }
+            }
+
+        }
+        return false;
+    }
+
+    void setQueueContext(final QueueContext queueContext)
+    {
+        _queueContext = queueContext;
+    }
+
+    QueueContext getQueueContext()
+    {
+        return _queueContext;
+    }
+
+    @Override
+    public MessageInstance.StealableConsumerAcquiredState<TransferQueueConsumer> getOwningState()
+    {
+        return _owningState;
+    }
+
+    public boolean isSuspended()
+    {
+        return _target.isSuspended();
+    }
+
+    boolean wouldSuspend(final TransferQueueEntry entry)
+    {
+        return _target.wouldSuspend(entry);
+    }
+
+    public TransferTarget getTarget()
+    {
+        return _target;
+    }
+
+    @Override
+    public void acquisitionRemoved(final QueueEntry queueEntry)
+    {
+
+    }
+
+    @Override
+    public long getConsumerNumber()
+    {
+        return 0;
+    }
+
+    @Override
+    public boolean resend(final QueueEntry queueEntry)
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isClosed()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean acquires()
+    {
+        return true;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "$transfer";
+    }
+
+    @Override
+    public void close()
+    {
+
+    }
+
+    @Override
+    public void flush()
+    {
+
+    }
+
+    @Override
+    public void externalStateChange()
+    {
+
+    }
+
+    @Override
+    public Object getIdentifier()
+    {
+        return _identifier;
+    }
+
+    @Override
+    public boolean hasAvailableMessages()
+    {
+        return _transferQueue.hasAvailableMessages(this);
+    }
+
+    @Override
+    public void pullMessage()
+    {
+
+    }
+
+    public void send(final TransferQueueEntry entry)
+    {
+        _target.send(entry);
+    }
+
+    public void restoreCredit(final TransferQueueEntry entry)
+    {
+        _target.restoreCredit(entry.getMessage());
+    }
+
+    public void notifyWork()
+    {
+        _target.notifyWork();
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueEntry.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueEntry.java
new file mode 100644
index 0000000..8931bd4
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueEntry.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.transfer;
+
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.OrderedQueueEntry;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+
+public class TransferQueueEntry extends OrderedQueueEntry
+{
+
+    protected TransferQueueEntry(final TransferQueueEntryList queueEntryList)
+    {
+        super(queueEntryList);
+    }
+
+    public TransferQueueEntry(final TransferQueueEntryList queueEntryList,
+                              final ServerMessage message,
+                              final MessageEnqueueRecord messageEnqueueRecord)
+    {
+        super(queueEntryList, message, messageEnqueueRecord);
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueEntryList.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueEntryList.java
new file mode 100644
index 0000000..c8c632e
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueEntryList.java
@@ -0,0 +1,102 @@
+/*
+ *
+ * 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.transfer;
+
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.queue.OrderedBaseQueueEntryList;
+import org.apache.qpid.server.queue.OrderedQueueEntry;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.QueueEntryList;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.Action;
+
+public class TransferQueueEntryList extends OrderedBaseQueueEntryList<TransferQueue>
+{
+
+    private static final HeadCreator HEAD_CREATOR = new HeadCreator()
+    {
+        @Override
+        public TransferQueueEntry createHead(final QueueEntryList list)
+        {
+            return new TransferQueueEntry((TransferQueueEntryList) list);
+        }
+    };
+
+    public TransferQueueEntryList(final TransferQueue queue)
+    {
+        super(queue, HEAD_CREATOR);
+    }
+
+
+    @Override
+    protected OrderedQueueEntry createQueueEntry(final ServerMessage<?> message,
+                                                 final MessageEnqueueRecord enqueueRecord)
+    {
+        return new TransferQueueEntry(this, message, enqueueRecord);
+    }
+
+    @Override
+    public void onAcquiredByConsumer(final QueueEntry queueEntry, final MessageInstanceConsumer consumer)
+    {
+
+    }
+
+    @Override
+    public void onNoLongerAcquiredByConsumer(final QueueEntry queueEntry)
+    {
+
+    }
+
+    @Override
+    public void requeue(final QueueEntry queueEntry)
+    {
+
+    }
+
+    @Override
+    public boolean isHeld(final QueueEntry queueEntry, final long evaluationTime)
+    {
+        return false;
+    }
+
+    @Override
+    public void dequeue(final QueueEntry queueEntry)
+    {
+
+    }
+
+    @Override
+    public int routeToAlternate(final QueueEntry queueEntry,
+                                final Action<? super BaseMessageInstance> action,
+                                final ServerTransaction txn)
+    {
+        return 0;
+    }
+
+    @Override
+    public int getMaximumDeliveryAttempts()
+    {
+        return 0;
+    }
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueImpl.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueImpl.java
new file mode 100644
index 0000000..ce81bb7
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferQueueImpl.java
@@ -0,0 +1,409 @@
+/*
+ *
+ * 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.transfer;
+
+import java.nio.charset.StandardCharsets;
+import java.security.AccessControlException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.InstanceProperties;
+import org.apache.qpid.server.message.MessageReference;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.NamedAddressSpace;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.security.SecurityToken;
+import org.apache.qpid.server.store.MessageDurability;
+import org.apache.qpid.server.store.MessageEnqueueRecord;
+import org.apache.qpid.server.store.StorableMessageMetaData;
+import org.apache.qpid.server.txn.AutoCommitTransaction;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.Action;
+import org.apache.qpid.server.virtualhost.VirtualHostUnavailableException;
+
+public class TransferQueueImpl implements TransferQueue
+{
+    private static final UUID TRANSFER_QUEUE_ID = UUID.nameUUIDFromBytes("$transfer".getBytes(StandardCharsets.UTF_8));
+
+    private static final int RECOVERING = 1;
+    private static final int COMPLETING_RECOVERY = 2;
+    private static final int RECOVERED = 3;
+
+    private final AtomicInteger _recovering = new AtomicInteger(RECOVERING);
+    private final AtomicInteger _enqueuingWhileRecovering = new AtomicInteger(0);
+
+    private final ConcurrentLinkedQueue<EnqueueRequest> _postRecoveryQueue = new ConcurrentLinkedQueue<>();
+
+    private final VirtualHost<?> _virtualHost;
+
+    private final TransferQueueEntryList _queueEntryList;
+    private Collection<TransferQueueConsumer> _consumers = new CopyOnWriteArrayList<>();
+
+
+    public TransferQueueImpl(final VirtualHost<?> virtualHost)
+    {
+        _virtualHost = virtualHost;
+        _queueEntryList = new TransferQueueEntryList(this);
+    }
+
+    @Override
+    public void enqueue(final ServerMessage message,
+                        final Action<? super BaseMessageInstance> action,
+                        final MessageEnqueueRecord enqueueRecord)
+    {
+        if(_recovering.get() != RECOVERED)
+        {
+            _enqueuingWhileRecovering.incrementAndGet();
+
+            boolean addedToRecoveryQueue;
+            try
+            {
+                if(addedToRecoveryQueue = (_recovering.get() == RECOVERING))
+                {
+                    _postRecoveryQueue.add(new EnqueueRequest(message, action, enqueueRecord));
+                }
+            }
+            finally
+            {
+                _enqueuingWhileRecovering.decrementAndGet();
+            }
+
+            if(!addedToRecoveryQueue)
+            {
+                while(_recovering.get() != RECOVERED)
+                {
+                    Thread.yield();
+                }
+                doEnqueue(message, action, enqueueRecord);
+            }
+        }
+        else
+        {
+            doEnqueue(message, action, enqueueRecord);
+        }
+
+
+    }
+
+    @Override
+    public void recover(final ServerMessage<?> message, final MessageEnqueueRecord enqueueRecord)
+    {
+        doEnqueue(message, null, enqueueRecord);
+    }
+
+    @Override
+    public final void completeRecovery()
+    {
+        if(_recovering.compareAndSet(RECOVERING, COMPLETING_RECOVERY))
+        {
+            while(_enqueuingWhileRecovering.get() != 0)
+            {
+                Thread.yield();
+            }
+
+            // at this point we can assert that any new enqueue to the queue will not try to put into the post recovery
+            // queue (because the state is no longer RECOVERING, but also no threads are currently trying to enqueue
+            // because the _enqueuingWhileRecovering count is 0.
+
+            enqueueFromPostRecoveryQueue();
+
+            _recovering.set(RECOVERED);
+
+        }
+    }
+
+    @Override
+    public VirtualHost<?> getVirtualHost()
+    {
+        return _virtualHost;
+    }
+
+    private void enqueueFromPostRecoveryQueue()
+    {
+        while(!_postRecoveryQueue.isEmpty())
+        {
+            EnqueueRequest request = _postRecoveryQueue.poll();
+            MessageReference<?> messageReference = request.getMessage();
+            doEnqueue(messageReference.getMessage(), request.getAction(), request.getEnqueueRecord());
+            messageReference.release();
+        }
+    }
+
+
+
+    protected void doEnqueue(final ServerMessage message, final Action<? super BaseMessageInstance> action, MessageEnqueueRecord enqueueRecord)
+    {
+        final TransferQueueEntry entry = (TransferQueueEntry) _queueEntryList.add(message, enqueueRecord);
+        for (TransferQueueConsumer consumer : getConsumers())
+        {
+            if (consumer.hasInterest(entry))
+            {
+                consumer.notifyWork();
+            }
+        }
+    }
+
+    private Collection<TransferQueueConsumer> getConsumers()
+    {
+        return _consumers;
+    }
+
+    @Override
+    public TransferQueueConsumer addConsumer(final TransferTarget target,
+                                             final String consumerName)
+    {
+
+
+
+        TransferQueueConsumer consumer = new TransferQueueConsumer(this,
+                                                                   target,
+                                                                   consumerName);
+
+        QueueContext queueContext = new QueueContext(_queueEntryList.getHead());
+        consumer.setQueueContext(queueContext);
+        _consumers.add(consumer);
+        consumer.notifyWork();
+
+        return consumer;
+    }
+
+    boolean hasAvailableMessages(final TransferQueueConsumer queueConsumer)
+    {
+        return getNextAvailableEntry(queueConsumer) != null;
+    }
+
+
+    void setLastSeenEntry(final TransferQueueConsumer sub, final TransferQueueEntry entry)
+    {
+        QueueContext subContext = sub.getQueueContext();
+        if (subContext != null)
+        {
+            QueueEntry releasedEntry = subContext.getReleasedEntry();
+
+            QueueContext._lastSeenUpdater.set(subContext, entry);
+            if(releasedEntry == entry)
+            {
+                QueueContext._releasedUpdater.compareAndSet(subContext, releasedEntry, null);
+            }
+        }
+    }
+
+    TransferQueueEntry getNextAvailableEntry(final TransferQueueConsumer sub)
+    {
+        QueueContext context = sub.getQueueContext();
+        if(context != null)
+        {
+            QueueEntry lastSeen = context.getLastSeenEntry();
+            QueueEntry releasedNode = context.getReleasedEntry();
+
+            TransferQueueEntry node =
+                    (TransferQueueEntry) ((releasedNode != null && lastSeen.compareTo(releasedNode) >= 0)
+                                        ? releasedNode : _queueEntryList.next(lastSeen));
+
+            boolean expired = false;
+            while (node != null
+                   && (!node.isAvailable()
+                       || (expired = node.expired())
+                       || !sub.hasInterest(node)))
+            {
+                if (expired)
+                {
+                    expired = false;
+                    if (node.acquire())
+                    {
+                        dequeueEntry(node);
+                    }
+                }
+
+                if(QueueContext._lastSeenUpdater.compareAndSet(context, lastSeen, node))
+                {
+                    QueueContext._releasedUpdater.compareAndSet(context, releasedNode, null);
+                }
+
+                lastSeen = context.getLastSeenEntry();
+                releasedNode = context.getReleasedEntry();
+                node = (TransferQueueEntry) ((releasedNode != null && lastSeen.compareTo(releasedNode) >= 0)
+                                        ? releasedNode
+                                        : _queueEntryList.next(lastSeen));
+            }
+            return node;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    private void dequeueEntry(final QueueEntry node)
+    {
+        ServerTransaction txn = new AutoCommitTransaction(_virtualHost.getMessageStore());
+        dequeueEntry(node, txn);
+    }
+
+    private void dequeueEntry(final QueueEntry node, ServerTransaction txn)
+    {
+        txn.dequeue(node.getEnqueueRecord(),
+                    new ServerTransaction.Action()
+                    {
+
+                        public void postCommit()
+                        {
+                            node.delete();
+                        }
+
+                        public void onRollback()
+                        {
+
+                        }
+                    });
+    }
+
+    @Override
+    public boolean isDurable()
+    {
+        return true;
+    }
+
+    @Override
+    public boolean isDeleted()
+    {
+        return false;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "$transfer";
+    }
+
+    @Override
+    public NamedAddressSpace getAddressSpace()
+    {
+        return _virtualHost;
+    }
+
+    @Override
+    public void authorisePublish(final SecurityToken token, final Map<String, Object> arguments)
+            throws AccessControlException
+    {
+        // TODO
+    }
+
+    @Override
+    public <M extends ServerMessage<? extends StorableMessageMetaData>> int send(final M message,
+                                                                                 final String routingAddress,
+                                                                                 final InstanceProperties instanceProperties,
+                                                                                 final ServerTransaction txn,
+                                                                                 final Action<? super BaseMessageInstance> postEnqueueAction)
+    {
+        if (_virtualHost.getState() != State.ACTIVE)
+        {
+            throw new VirtualHostUnavailableException(this._virtualHost);
+        }
+
+        if(!message.isReferenced(this))
+        {
+            txn.enqueue(this, message, new ServerTransaction.EnqueueAction()
+            {
+                MessageReference _reference = message.newReference();
+
+                public void postCommit(MessageEnqueueRecord... records)
+                {
+                    try
+                    {
+                        TransferQueueImpl.this.enqueue(message, postEnqueueAction, records[0]);
+                    }
+                    finally
+                    {
+                        _reference.release();
+                    }
+                }
+
+                public void onRollback()
+                {
+                    _reference.release();
+                }
+            });
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
+
+    }
+
+    @Override
+    public UUID getId()
+    {
+        return TRANSFER_QUEUE_ID;
+    }
+
+    @Override
+    public MessageDurability getMessageDurability()
+    {
+        return MessageDurability.DEFAULT;
+    }
+
+    public void flushConsumer(final TransferQueueConsumer consumer, final int count)
+    {
+
+    }
+
+    private static class EnqueueRequest
+    {
+        private final MessageReference<?> _message;
+        private final Action<? super BaseMessageInstance> _action;
+        private final MessageEnqueueRecord _enqueueRecord;
+
+        public EnqueueRequest(final ServerMessage message,
+                              final Action<? super BaseMessageInstance> action,
+                              final MessageEnqueueRecord enqueueRecord)
+        {
+            _enqueueRecord = enqueueRecord;
+            _message = message.newReference();
+            _action = action;
+        }
+
+        public MessageReference<?> getMessage()
+        {
+            return _message;
+        }
+
+        public Action<? super BaseMessageInstance> getAction()
+        {
+            return _action;
+        }
+
+        public MessageEnqueueRecord getEnqueueRecord()
+        {
+            return _enqueueRecord;
+        }
+    }
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferTarget.java
similarity index 66%
copy from broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
copy to broker-core/src/main/java/org/apache/qpid/server/transfer/TransferTarget.java
index d2aff53..7539dd5 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/queue/QueueEntryListBase.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transfer/TransferTarget.java
@@ -18,8 +18,24 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.queue;
+package org.apache.qpid.server.transfer;
 
-public interface QueueEntryListBase extends QueueEntryList
+import java.util.Collection;
+
+import org.apache.qpid.server.message.ServerMessage;
+
+public interface TransferTarget
 {
+
+    void notifyWork();
+
+    Collection<String> getGlobalAddressDomains();
+
+    void send(TransferQueueEntry entry);
+
+    void restoreCredit(ServerMessage message);
+
+    boolean wouldSuspend(TransferQueueEntry entry);
+
+    boolean isSuspended();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java b/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
index fe5a219..bb77538 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/AbstractAMQPConnection.java
@@ -331,18 +331,18 @@
     @Override
     public void pushScheduler(final NetworkConnectionScheduler networkConnectionScheduler)
     {
-        if(_network instanceof NonBlockingConnection)
+        if(_network instanceof NonBlockingInboundConnection)
         {
-            ((NonBlockingConnection) _network).pushScheduler(networkConnectionScheduler);
+            ((NonBlockingInboundConnection) _network).pushScheduler(networkConnectionScheduler);
         }
     }
 
     @Override
     public NetworkConnectionScheduler popScheduler()
     {
-        if(_network instanceof NonBlockingConnection)
+        if(_network instanceof NonBlockingInboundConnection)
         {
-            return ((NonBlockingConnection) _network).popScheduler();
+            return ((NonBlockingInboundConnection) _network).popScheduler();
         }
         return null;
     }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NetworkConnectionScheduler.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NetworkConnectionScheduler.java
index 9828d46..faa327f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NetworkConnectionScheduler.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NetworkConnectionScheduler.java
@@ -119,7 +119,7 @@
         }
     }
 
-    void processConnection(final NonBlockingConnection connection)
+    void processConnection(final SchedulableConnection connection)
     {
         Thread.currentThread().setName(connection.getThreadName());
         connection.doPreWork();
@@ -235,12 +235,12 @@
         return _selectorThread.cancelAcceptingSocket(serverSocket);
     }
 
-    public void addConnection(final NonBlockingConnection connection)
+    public void addConnection(final SchedulableConnection connection)
     {
         _selectorThread.addConnection(connection);
     }
 
-    public void removeConnection(final NonBlockingConnection connection)
+    public void removeConnection(final SchedulableConnection connection)
     {
         _selectorThread.removeConnection(connection);
     }
@@ -250,7 +250,7 @@
         return _poolSize;
     }
 
-    public void schedule(final NonBlockingConnection connection)
+    public void schedule(final SchedulableConnection connection)
     {
         _selectorThread.addToWork(connection);
     }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnection.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnection.java
index 7eaa721..ff64fe8 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnection.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnection.java
@@ -1,5 +1,5 @@
 /*
-*
+ *
  * 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
@@ -29,7 +29,6 @@
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -40,231 +39,232 @@
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.bytebuffer.QpidByteBuffer;
-import org.apache.qpid.server.model.port.AmqpPort;
 import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
 import org.apache.qpid.transport.ByteBufferSender;
 import org.apache.qpid.transport.network.Ticker;
-import org.apache.qpid.transport.network.TransportEncryption;
 import org.apache.qpid.util.SystemUtils;
 
-public class NonBlockingConnection implements ServerNetworkConnection, ByteBufferSender
+public abstract class NonBlockingConnection implements SchedulableConnection
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(NonBlockingConnection.class);
 
+    final AtomicLong _usedOutboundMessageSpace = new AtomicLong();
     private final SocketChannel _socketChannel;
-    private NonBlockingConnectionDelegate _delegate;
     private final Deque<NetworkConnectionScheduler> _schedulerDeque = new ConcurrentLinkedDeque<>();
-    private final ConcurrentLinkedQueue<QpidByteBuffer> _buffers = new ConcurrentLinkedQueue<>();
-
-    private final String _remoteSocketAddress;
-    private final AtomicBoolean _closed = new AtomicBoolean(false);
-    private final ProtocolEngine _protocolEngine;
-    private final Runnable _onTransportEncryptionAction;
-    private final AtomicLong _usedOutboundMessageSpace = new AtomicLong();
-    private final long _outboundMessageBufferLimit;
-
-    private volatile boolean _fullyWritten = true;
-
-    private boolean _partialRead = false;
-
-    private final AmqpPort _port;
+    private final String _remoteAddressString;
     private final AtomicBoolean _scheduled = new AtomicBoolean();
-    private volatile long _scheduledTime;
-    private volatile boolean _unexpectedByteBufferSizeReported;
-    private final String _threadName;
-    private volatile SelectorThread.SelectionTask _selectionTask;
-    private Iterator<Runnable> _pendingIterator;
     private final AtomicLong _maxWriteIdleMillis = new AtomicLong();
     private final AtomicLong _maxReadIdleMillis = new AtomicLong();
-    private final List<SchedulingDelayNotificationListener> _schedulingDelayNotificationListeners = new CopyOnWriteArrayList<>();
-    private final AtomicBoolean _hasShutdown = new AtomicBoolean();
+    private final List<SchedulingDelayNotificationListener>
+            _schedulingDelayNotificationListeners = new CopyOnWriteArrayList<>();
+    private final String _threadName;
+    private final ConcurrentLinkedQueue<QpidByteBuffer> _buffers = new ConcurrentLinkedQueue<>();
+    private NonBlockingConnectionDelegate _delegate;
+    private final AtomicBoolean _closed = new AtomicBoolean(false);
 
-    public NonBlockingConnection(SocketChannel socketChannel,
-                                 ProtocolEngine protocolEngine,
-                                 final Set<TransportEncryption> encryptionSet,
-                                 final Runnable onTransportEncryptionAction,
-                                 final NetworkConnectionScheduler scheduler,
-                                 final AmqpPort port)
+    private volatile SelectorThread.SelectionTask _selectionTask;
+    private volatile long _scheduledTime;
+    private final AtomicBoolean _hasShutdown = new AtomicBoolean();
+    private final AtomicBoolean _unexpectedByteBufferSizeReported = new AtomicBoolean();
+    private final ProtocolEngine _protocolEngine;
+    private volatile Iterator<Runnable> _pendingIterator;
+    private volatile boolean _fullyWritten = true;
+    private volatile boolean _partialRead = false;
+
+    protected NonBlockingConnection(final SocketChannel socketChannel, ProtocolEngine protocolEngine,
+                                    final NetworkConnectionScheduler scheduler,
+                                    String remoteAddressString)
     {
         _socketChannel = socketChannel;
-        pushScheduler(scheduler);
-
         _protocolEngine = protocolEngine;
-        _onTransportEncryptionAction = onTransportEncryptionAction;
-
-        _remoteSocketAddress = _socketChannel.socket().getRemoteSocketAddress().toString();
-        _port = port;
-        _threadName = SelectorThread.IO_THREAD_NAME_PREFIX + _remoteSocketAddress.toString();
-
-        _outboundMessageBufferLimit = (long) _port.getContextValue(Long.class,
-                                                                   AmqpPort.PORT_AMQP_OUTBOUND_MESSAGE_BUFFER_SIZE);
-
+        _remoteAddressString = remoteAddressString;
+        _threadName = SelectorThread.IO_THREAD_NAME_PREFIX + _remoteAddressString;
+        pushScheduler(scheduler);
         protocolEngine.setWorkListener(new Action<ProtocolEngine>()
         {
             @Override
             public void performAction(final ProtocolEngine object)
             {
-                if(!_scheduled.get())
+                NetworkConnectionScheduler scheduler = getScheduler();
+                if(scheduler != null && !_scheduled.get())
                 {
                     getScheduler().schedule(NonBlockingConnection.this);
                 }
             }
         });
 
-        if(encryptionSet.size() == 1)
-        {
-            setTransportEncryption(encryptionSet.iterator().next());
-        }
-        else
-        {
-            _delegate = new NonBlockingConnectionUndecidedDelegate(this);
-        }
 
     }
 
-    String getThreadName()
+    @Override
+    public final String getThreadName()
     {
         return _threadName;
     }
 
-    public boolean isPartialRead()
+
+    protected final String getRemoteAddressString()
     {
-        return _partialRead;
+        return _remoteAddressString;
     }
 
-    Ticker getTicker()
+    protected final boolean isClosed()
     {
-        return _protocolEngine.getAggregateTicker();
+        return _closed.get();
     }
 
-    SocketChannel getSocketChannel()
+    protected final boolean setClosed()
+    {
+        return _closed.compareAndSet(false,true);
+    }
+
+    @Override
+    public final SocketChannel getSocketChannel()
     {
         return _socketChannel;
     }
 
+
     @Override
-    public void start()
+    public final SocketAddress getRemoteAddress()
     {
+        return getSocketChannel().socket().getRemoteSocketAddress();
     }
 
     @Override
-    public ByteBufferSender getSender()
+    public final SocketAddress getLocalAddress()
     {
-        return this;
+        return getSocketChannel().socket().getLocalSocketAddress();
+    }
+
+
+    public final void pushScheduler(NetworkConnectionScheduler scheduler)
+    {
+        _schedulerDeque.addFirst(scheduler);
+    }
+
+    public final NetworkConnectionScheduler popScheduler()
+    {
+        return _schedulerDeque.removeFirst();
     }
 
     @Override
-    public void close()
+    public final NetworkConnectionScheduler getScheduler()
     {
-        LOGGER.debug("Closing " + _remoteSocketAddress);
-        if(_closed.compareAndSet(false,true))
-        {
-            _protocolEngine.notifyWork();
-            _selectionTask.wakeup();
-        }
+        return _schedulerDeque.peekFirst();
     }
 
     @Override
-    public SocketAddress getRemoteAddress()
-    {
-        return _socketChannel.socket().getRemoteSocketAddress();
-    }
-
-    @Override
-    public SocketAddress getLocalAddress()
-    {
-        return _socketChannel.socket().getLocalSocketAddress();
-    }
-
-    @Override
-    public void setMaxWriteIdleMillis(final long millis)
-    {
-        _maxWriteIdleMillis.set(millis);
-    }
-
-    @Override
-    public void setMaxReadIdleMillis(final long millis)
-    {
-        _maxReadIdleMillis.set(millis);
-    }
-
-    @Override
-    public Principal getPeerPrincipal()
+    public final Principal getPeerPrincipal()
     {
         return _delegate.getPeerPrincipal();
     }
 
     @Override
-    public Certificate getPeerCertificate()
+    public final Certificate getPeerCertificate()
     {
         return _delegate.getPeerCertificate();
     }
 
     @Override
-    public long getMaxReadIdleMillis()
+    public final String getTransportInfo()
+    {
+        return _delegate.getTransportInfo();
+    }
+
+
+    @Override
+    public final SelectorThread.SelectionTask getSelectionTask()
+    {
+        return _selectionTask;
+    }
+
+    @Override
+    public final void setSelectionTask(final SelectorThread.SelectionTask selectionTask)
+    {
+        _selectionTask = selectionTask;
+    }
+
+    @Override
+    public final boolean setScheduled()
+    {
+        final boolean scheduled = _scheduled.compareAndSet(false, true);
+        if (scheduled)
+        {
+            _scheduledTime = System.currentTimeMillis();
+        }
+        return scheduled;
+    }
+
+    @Override
+    public final void clearScheduled()
+    {
+        _scheduled.set(false);
+        _scheduledTime = 0;
+    }
+
+    @Override
+    public final long getScheduledTime()
+    {
+        return _scheduledTime;
+    }
+
+    @Override
+    public final void setMaxWriteIdleMillis(final long millis)
+    {
+        _maxWriteIdleMillis.set(millis);
+    }
+
+    @Override
+    public final void setMaxReadIdleMillis(final long millis)
+    {
+        _maxReadIdleMillis.set(millis);
+    }
+
+    @Override
+    public final long getMaxReadIdleMillis()
     {
         return _maxReadIdleMillis.get();
     }
 
     @Override
-    public long getMaxWriteIdleMillis()
+    public final long getMaxWriteIdleMillis()
     {
         return _maxWriteIdleMillis.get();
     }
-
     @Override
-    public void reserveOutboundMessageSpace(long size)
-    {
-        if (_usedOutboundMessageSpace.addAndGet(size) > _outboundMessageBufferLimit)
-        {
-            _protocolEngine.setMessageAssignmentSuspended(true, false);
-        }
-    }
-
-    @Override
-    public String getTransportInfo()
-    {
-        return _delegate.getTransportInfo();
-    }
-
-    boolean wantsRead()
-    {
-        return _fullyWritten;
-    }
-
-    boolean wantsWrite()
-    {
-        return !_fullyWritten;
-    }
-
-    public boolean isStateChanged()
+    public final boolean isStateChanged()
     {
         return _protocolEngine.hasWork();
     }
 
-    public void doPreWork()
+    @Override
+    public final boolean wantsRead()
     {
-        if (!_closed.get())
-        {
-            long currentTime = System.currentTimeMillis();
-            long schedulingDelay = currentTime - getScheduledTime();
-            if (!_schedulingDelayNotificationListeners.isEmpty())
-            {
-                for (SchedulingDelayNotificationListener listener : _schedulingDelayNotificationListeners)
-                {
-                    listener.notifySchedulingDelay(schedulingDelay);
-                }
-            }
-        }
+        return _fullyWritten;
     }
 
+    @Override
+    public final boolean wantsWrite()
+    {
+        return !_fullyWritten;
+    }
+
+    @Override
+    public final boolean isPartialRead()
+    {
+        return _partialRead;
+    }
+
+    @Override
     public boolean doWork()
     {
         _protocolEngine.clearWork();
-        if (!_closed.get())
+        try
         {
-            try
+
+            if (!isClosed() && (!wantsConnect() || completeConnection()))
             {
                 long currentTime = System.currentTimeMillis();
                 int tick = getTicker().getTimeToNextTick(currentTime);
@@ -278,14 +278,16 @@
 
                 boolean processPendingComplete = processPending();
 
-                if(processPendingComplete)
+                if (processPendingComplete)
                 {
                     _pendingIterator = null;
                     _protocolEngine.setTransportBlockedForWriting(false);
                     boolean dataRead = doRead();
-                    _protocolEngine.setTransportBlockedForWriting(!doWrite());
+                    _fullyWritten = doWrite();
+                    _protocolEngine.setTransportBlockedForWriting(!_fullyWritten);
 
-                    if (!_fullyWritten || dataRead || (_delegate.needsWork() && _delegate.getNetInputBuffer().position() != 0))
+                    if (!_fullyWritten || dataRead || (_delegate.needsWork()
+                                                       && _delegate.getNetInputBuffer().position() != 0))
                     {
                         _protocolEngine.notifyWork();
                     }
@@ -299,34 +301,33 @@
                 {
                     _protocolEngine.notifyWork();
                 }
-
-            }
-            catch (IOException |
-                    ConnectionScopedRuntimeException e)
-            {
-                if (LOGGER.isDebugEnabled())
-                {
-                    LOGGER.debug("Exception performing I/O for connection '{}'",
-                                 _remoteSocketAddress, e);
-                }
-                else
-                {
-                    LOGGER.info("Exception performing I/O for connection '{}' : {}",
-                                _remoteSocketAddress, e.getMessage());
-                }
-
-                if(_closed.compareAndSet(false,true))
-                {
-                    _protocolEngine.notifyWork();
-                }
-            }
-            finally
-            {
-                _protocolEngine.setIOThread(null);
             }
         }
+        catch (IOException |
+                ConnectionScopedRuntimeException e)
+        {
+            if (LOGGER.isDebugEnabled())
+            {
+                LOGGER.debug("Exception performing I/O for connection '{}'",
+                             getRemoteAddressString(), e);
+            }
+            else
+            {
+                LOGGER.info("Exception performing I/O for connection '{}' : {}",
+                            getRemoteAddressString(), e.getMessage());
+            }
 
-        final boolean closed = _closed.get();
+            if(setClosed())
+            {
+                _protocolEngine.notifyWork();
+            }
+        }
+        finally
+        {
+            _protocolEngine.setIOThread(null);
+        }
+
+        final boolean closed = isClosed();
         if (closed)
         {
             shutdown();
@@ -336,17 +337,12 @@
 
     }
 
-    @Override
-    public void addSchedulingDelayNotificationListeners(final SchedulingDelayNotificationListener listener)
+    private boolean completeConnection() throws IOException
     {
-        _schedulingDelayNotificationListeners.add(listener);
+        boolean finishConnect = getSocketChannel().finishConnect();
+        return finishConnect  && !wantsConnect();
     }
 
-    @Override
-    public void removeSchedulingDelayNotificationListeners(final SchedulingDelayNotificationListener listener)
-    {
-        _schedulingDelayNotificationListeners.remove(listener);
-    }
 
     private boolean processPending() throws IOException
     {
@@ -355,14 +351,14 @@
             _pendingIterator = _protocolEngine.processPendingIterator();
         }
 
-        final int networkBufferSize = _port.getNetworkBufferSize();
+        final int networkBufferSize = getNetworkBufferSize();
 
         while(_pendingIterator.hasNext())
         {
             long size = getBufferedSize();
             if(size >= networkBufferSize)
             {
-                doWrite();
+                _fullyWritten = doWrite();
                 long bytesWritten = size - getBufferedSize();
                 if(bytesWritten < (networkBufferSize / 2))
                 {
@@ -379,19 +375,123 @@
         boolean complete = !_pendingIterator.hasNext();
         if (getBufferedSize() >= networkBufferSize)
         {
-            doWrite();
+            _fullyWritten = doWrite();
             complete &= getBufferedSize() < networkBufferSize /2;
         }
         return complete;
     }
 
-    private long getBufferedSize()
+    protected abstract int getNetworkBufferSize();
+
+
+    @Override
+    public final void doPreWork()
+    {
+        if (!isClosed())
+        {
+            long currentTime = System.currentTimeMillis();
+            long schedulingDelay = currentTime - getScheduledTime();
+            if (!_schedulingDelayNotificationListeners.isEmpty())
+            {
+                for (SchedulingDelayNotificationListener listener : _schedulingDelayNotificationListeners)
+                {
+                    listener.notifySchedulingDelay(schedulingDelay);
+                }
+            }
+        }
+    }
+
+
+    /**
+     * doRead is not reentrant.
+     */
+    boolean doRead() throws IOException
+    {
+        _partialRead = false;
+        if(!isClosed() && _delegate.readyForRead())
+        {
+            int readData = readFromNetwork();
+
+            if (readData > 0)
+            {
+                return _delegate.processData();
+            }
+            else
+            {
+                return false;
+            }
+        }
+        else
+        {
+            return false;
+        }
+    }
+
+    @Override
+    public long writeToTransport(Collection<QpidByteBuffer> buffers) throws IOException
+    {
+        long written  = QpidByteBuffer.write(getSocketChannel(), buffers);
+        if (LOGGER.isDebugEnabled())
+        {
+            LOGGER.debug("Written " + written + " bytes");
+        }
+        return written;
+    }
+
+    protected int readFromNetwork() throws IOException
+    {
+        QpidByteBuffer buffer = _delegate.getNetInputBuffer();
+
+        int read = buffer.read(getSocketChannel());
+        if (read == -1)
+        {
+            setClosed();
+        }
+
+        _partialRead = read != 0;
+
+        if (LOGGER.isDebugEnabled())
+        {
+            LOGGER.debug("Read " + read + " byte(s)");
+        }
+        return read;
+    }
+
+
+
+
+    @Override
+    public final void addSchedulingDelayNotificationListeners(final SchedulingDelayNotificationListener listener)
+    {
+        _schedulingDelayNotificationListeners.add(listener);
+    }
+
+    @Override
+    public final void removeSchedulingDelayNotificationListeners(final SchedulingDelayNotificationListener listener)
+    {
+        _schedulingDelayNotificationListeners.remove(listener);
+    }
+
+    @Override
+    public final ByteBufferSender getSender()
+    {
+        return this;
+    }
+
+    @Override
+    public final boolean isDirectBufferPreferred()
+    {
+        return true;
+    }
+
+    private final long getBufferedSize()
     {
         // Avoids iterator garbage if empty
         if (_buffers.isEmpty())
         {
             return 0L;
         }
+
         long totalSize = 0L;
         for(QpidByteBuffer buf : _buffers)
         {
@@ -400,7 +500,44 @@
         return totalSize;
     }
 
-    private void shutdown()
+    final boolean doWrite() throws IOException
+    {
+        boolean fullyWritten = _delegate.doWrite(_buffers);
+        while(!_buffers.isEmpty())
+        {
+            QpidByteBuffer buf = _buffers.peek();
+            if(buf.hasRemaining())
+            {
+                break;
+            }
+            _buffers.poll();
+            buf.dispose();
+        }
+        if (fullyWritten)
+        {
+            _usedOutboundMessageSpace.set(0);
+        }
+        return fullyWritten;
+
+    }
+
+    @Override
+    public final void send(final QpidByteBuffer msg)
+    {
+
+        if (isClosed())
+        {
+            LOGGER.warn("Send ignored as the connection is already closed");
+        }
+        else if (msg.remaining() > 0)
+        {
+            _buffers.add(msg.duplicate());
+        }
+        msg.position(msg.limit());
+    }
+
+
+    protected final void shutdown()
     {
         if (_hasShutdown.getAndSet(true))
         {
@@ -411,7 +548,9 @@
         {
             shutdownInput();
             shutdownFinalWrite();
+
             _protocolEngine.closed();
+
             shutdownOutput();
         }
         finally
@@ -428,12 +567,12 @@
                 }
                 finally
                 {
-                    _socketChannel.close();
+                    getSocketChannel().close();
                 }
             }
             catch (IOException e)
             {
-                LOGGER.info("Exception closing socket '{}': {}", _remoteSocketAddress, e.getMessage());
+                LOGGER.info("Exception closing socket '{}': {}", getRemoteAddressString(), e.getMessage());
             }
 
             if (SystemUtils.isWindows())
@@ -454,7 +593,7 @@
         }
         catch (IOException e)
         {
-            LOGGER.info("Exception performing final write/close for '{}': {}", _remoteSocketAddress, e.getMessage());
+            LOGGER.info("Exception performing final write/close for '{}': {}", getRemoteAddressString(), e.getMessage());
         }
     }
 
@@ -464,11 +603,11 @@
         {
             try
             {
-                _socketChannel.shutdownOutput();
+                getSocketChannel().shutdownOutput();
             }
             catch (IOException e)
             {
-                LOGGER.info("Exception closing socket '{}': {}", _remoteSocketAddress, e.getMessage());
+                LOGGER.info("Exception closing socket '{}': {}", getRemoteAddressString(), e.getMessage());
             }
             finally
             {
@@ -484,11 +623,11 @@
         {
             try
             {
-                _socketChannel.shutdownInput();
+                getSocketChannel().shutdownInput();
             }
             catch (IOException e)
             {
-                LOGGER.info("Exception shutting down input for '{}': {}", _remoteSocketAddress, e.getMessage());
+                LOGGER.info("Exception shutting down input for '{}': {}", getRemoteAddressString(), e.getMessage());
             }
             finally
             {
@@ -497,197 +636,78 @@
         }
     }
 
-    /**
-     * doRead is not reentrant.
-     */
-    boolean doRead() throws IOException
+
+    @Override
+    public final void start()
     {
-        _partialRead = false;
-        if(!_closed.get() && _delegate.readyForRead())
-        {
-            int readData = readFromNetwork();
-
-            if (readData > 0)
-            {
-                return _delegate.processData();
-            }
-            else
-            {
-                return false;
-            }
-        }
-        else
-        {
-            return false;
-        }
-    }
-
-    long writeToTransport(Collection<QpidByteBuffer> buffers) throws IOException
-    {
-        long written  = QpidByteBuffer.write(_socketChannel, buffers);
-        if (LOGGER.isDebugEnabled())
-        {
-            LOGGER.debug("Written " + written + " bytes");
-        }
-        return written;
-    }
-
-    private boolean doWrite() throws IOException
-    {
-        _fullyWritten = _delegate.doWrite(_buffers);
-        while(!_buffers.isEmpty())
-        {
-            QpidByteBuffer buf = _buffers.peek();
-            if(buf.hasRemaining())
-            {
-                break;
-            }
-            _buffers.poll();
-            buf.dispose();
-        }
-        if (_fullyWritten)
-        {
-            _usedOutboundMessageSpace.set(0);
-        }
-        return _fullyWritten;
-
-    }
-
-    protected int readFromNetwork() throws IOException
-    {
-        QpidByteBuffer buffer = _delegate.getNetInputBuffer();
-
-        int read = buffer.read(_socketChannel);
-        if (read == -1)
-        {
-            _closed.set(true);
-        }
-
-        _partialRead = read != 0;
-
-        if (LOGGER.isDebugEnabled())
-        {
-            LOGGER.debug("Read " + read + " byte(s)");
-        }
-        return read;
     }
 
     @Override
-    public boolean isDirectBufferPreferred()
+    public final void flush()
     {
-        return true;
     }
 
-    @Override
-    public void send(final QpidByteBuffer msg)
-    {
 
-        if (_closed.get())
+    @Override
+    public final void close()
+    {
+        LOGGER.debug("Closing " + getRemoteAddressString());
+        if(setClosed())
         {
-            LOGGER.warn("Send ignored as the connection is already closed");
+            _protocolEngine.notifyWork();
+            getSelectionTask().wakeup();
         }
-        else if (msg.remaining() > 0)
-        {
-            _buffers.add(msg.duplicate());
-        }
-        msg.position(msg.limit());
     }
 
+
     @Override
-    public void flush()
-    {
-    }
-
-    public final void pushScheduler(NetworkConnectionScheduler scheduler)
-    {
-        _schedulerDeque.addFirst(scheduler);
-    }
-
-    public final NetworkConnectionScheduler popScheduler()
-    {
-        return _schedulerDeque.removeFirst();
-    }
-
-    public final NetworkConnectionScheduler getScheduler()
-    {
-        return _schedulerDeque.peekFirst();
-    }
-
-    @Override
-    public String toString()
-    {
-        return "[NonBlockingConnection " + _remoteSocketAddress + "]";
-    }
-
     public void processAmqpData(QpidByteBuffer applicationData)
     {
         _protocolEngine.received(applicationData);
     }
 
-    public void setTransportEncryption(TransportEncryption transportEncryption)
-    {
-        NonBlockingConnectionDelegate oldDelegate = _delegate;
-        switch (transportEncryption)
-        {
-            case TLS:
-                _onTransportEncryptionAction.run();
-                _delegate = new NonBlockingConnectionTLSDelegate(this, _port);
-                break;
-            case NONE:
-                _delegate = new NonBlockingConnectionPlainDelegate(this, _port);
-                break;
-            default:
-                throw new IllegalArgumentException("unknown TransportEncryption " + transportEncryption);
-        }
-        if(oldDelegate != null)
-        {
-            QpidByteBuffer src = oldDelegate.getNetInputBuffer().duplicate();
-            src.flip();
-            _delegate.getNetInputBuffer().put(src);
-            src.dispose();
-        }
-        LOGGER.debug("Identified transport encryption as " + transportEncryption);
-    }
-
-    public boolean setScheduled()
-    {
-        final boolean scheduled = _scheduled.compareAndSet(false, true);
-        if (scheduled)
-        {
-            _scheduledTime = System.currentTimeMillis();
-        }
-        return scheduled;
-    }
-
-    public void clearScheduled()
-    {
-        _scheduled.set(false);
-        _scheduledTime = 0;
-    }
 
     @Override
-    public long getScheduledTime()
+    public final void reserveOutboundMessageSpace(long size)
     {
-        return _scheduledTime;
-    }
-
-    void reportUnexpectedByteBufferSizeUsage()
-    {
-        if (!_unexpectedByteBufferSizeReported)
+        if (_usedOutboundMessageSpace.addAndGet(size) > getOutboundMessageBufferLimit())
         {
-            LOGGER.info("At least one frame unexpectedly does not fit into default byte buffer size ({}B) on a connection {}.",
-                    _port.getNetworkBufferSize(), this.toString());
-            _unexpectedByteBufferSizeReported = true;
+            _protocolEngine.setMessageAssignmentSuspended(true, false);
         }
     }
 
-    public SelectorThread.SelectionTask getSelectionTask()
+
+    @Override
+    public final Ticker getTicker()
     {
-        return _selectionTask;
+        return _protocolEngine.getAggregateTicker();
     }
 
-    public void setSelectionTask(final SelectorThread.SelectionTask selectionTask)
+
+    protected abstract long getOutboundMessageBufferLimit();
+
+
+    public final void reportUnexpectedByteBufferSizeUsage()
     {
-        _selectionTask = selectionTask;
+        if (_unexpectedByteBufferSizeReported.compareAndSet(false,true))
+        {
+            LOGGER.info("At least one frame unexpectedly does not fit into default byte buffer size ({}B) on a connection {}.",
+                        getNetworkBufferSize(), this.toString());
+        }
+    }
+
+    protected NonBlockingConnectionDelegate getDelegate()
+    {
+        return _delegate;
+    }
+
+    protected void setDelegate(NonBlockingConnectionDelegate delegate)
+    {
+        _delegate = delegate;
+    }
+
+    public final ProtocolEngine getProtocolEngine()
+    {
+        return _protocolEngine;
     }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionPlainDelegate.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionPlainDelegate.java
index d4b1257..3bfd56e 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionPlainDelegate.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionPlainDelegate.java
@@ -24,7 +24,6 @@
 import java.security.cert.Certificate;
 import java.util.Collection;
 
-import org.apache.qpid.server.model.port.AmqpPort;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,14 +33,14 @@
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(NonBlockingConnectionPlainDelegate.class);
 
-    private final NonBlockingConnection _parent;
+    private final SchedulableConnection _parent;
     private final int _networkBufferSize;
     private volatile QpidByteBuffer _netInputBuffer;
 
-    public NonBlockingConnectionPlainDelegate(NonBlockingConnection parent, AmqpPort<?> port)
+    public NonBlockingConnectionPlainDelegate(SchedulableConnection parent, int networkBufferSize)
     {
         _parent = parent;
-        _networkBufferSize = port.getNetworkBufferSize();
+        _networkBufferSize = networkBufferSize;
         _netInputBuffer = QpidByteBuffer.allocateDirect(_networkBufferSize);
     }
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java
index 564eb64..cda7c04 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionTLSDelegate.java
@@ -19,19 +19,6 @@
 
 package org.apache.qpid.server.transport;
 
-import org.apache.qpid.bytebuffer.QpidByteBuffer;
-import org.apache.qpid.server.model.port.AmqpPort;
-import org.apache.qpid.server.util.ServerScopedRuntimeException;
-import org.apache.qpid.transport.network.security.ssl.SSLUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-
 import java.io.IOException;
 import java.security.Principal;
 import java.security.cert.Certificate;
@@ -41,12 +28,24 @@
 import java.util.List;
 import java.util.ListIterator;
 
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
 public class NonBlockingConnectionTLSDelegate implements NonBlockingConnectionDelegate
 {
     private static final Logger LOGGER = LoggerFactory.getLogger(NonBlockingConnectionTLSDelegate.class);
 
     private final SSLEngine _sslEngine;
-    private final NonBlockingConnection _parent;
+    private final SchedulableConnection _parent;
     private final int _networkBufferSize;
     private SSLEngineResult _status;
     private final List<QpidByteBuffer> _encryptedOutput = new ArrayList<>();
@@ -58,11 +57,11 @@
     private QpidByteBuffer _applicationBuffer;
 
 
-    public NonBlockingConnectionTLSDelegate(NonBlockingConnection parent, AmqpPort port)
+    public NonBlockingConnectionTLSDelegate(SchedulableConnection parent, int networkBufferSize, SSLEngine sslEngine)
     {
         _parent = parent;
-        _sslEngine = createSSLEngine(port);
-        _networkBufferSize = port.getNetworkBufferSize();
+        _sslEngine = sslEngine;
+        _networkBufferSize = networkBufferSize;
 
         final int tlsPacketBufferSize = _sslEngine.getSession().getPacketBufferSize();
         if (tlsPacketBufferSize > _networkBufferSize)
@@ -313,28 +312,6 @@
         }
     }
 
-    private SSLEngine createSSLEngine(AmqpPort<?> port)
-    {
-        SSLEngine sslEngine = port.getSSLContext().createSSLEngine();
-        sslEngine.setUseClientMode(false);
-        SSLUtil.updateEnabledTlsProtocols(sslEngine, port.getTlsProtocolWhiteList(), port.getTlsProtocolBlackList());
-        SSLUtil.updateEnabledCipherSuites(sslEngine, port.getTlsCipherSuiteWhiteList(), port.getTlsCipherSuiteBlackList());
-        if(port.getTlsCipherSuiteWhiteList() != null && !port.getTlsCipherSuiteWhiteList().isEmpty())
-        {
-            SSLUtil.useCipherOrderIfPossible(sslEngine);
-        }
-
-        if(port.getNeedClientAuth())
-        {
-            sslEngine.setNeedClientAuth(true);
-        }
-        else if(port.getWantClientAuth())
-        {
-            sslEngine.setWantClientAuth(true);
-        }
-        return sslEngine;
-    }
-
     @Override
     public QpidByteBuffer getNetInputBuffer()
     {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionUndecidedDelegate.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionUndecidedDelegate.java
index f80bd4e..6d7c723 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionUndecidedDelegate.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingConnectionUndecidedDelegate.java
@@ -19,22 +19,22 @@
 
 package org.apache.qpid.server.transport;
 
-import org.apache.qpid.bytebuffer.QpidByteBuffer;
-import org.apache.qpid.transport.network.TransportEncryption;
-
 import java.io.IOException;
 import java.security.Principal;
 import java.security.cert.Certificate;
 import java.util.Collection;
 
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.transport.network.TransportEncryption;
+
 public class NonBlockingConnectionUndecidedDelegate implements NonBlockingConnectionDelegate
 {
     private static final int NUMBER_OF_BYTES_FOR_TLS_CHECK = 6;
-    public final NonBlockingConnection _parent;
+    public final NonBlockingInboundConnection _parent;
 
     private QpidByteBuffer _netInputBuffer;
 
-    public NonBlockingConnectionUndecidedDelegate(NonBlockingConnection parent)
+    public NonBlockingConnectionUndecidedDelegate(NonBlockingInboundConnection parent)
     {
         _parent = parent;
         _netInputBuffer = QpidByteBuffer.allocateDirect(NUMBER_OF_BYTES_FOR_TLS_CHECK);
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingInboundConnection.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingInboundConnection.java
new file mode 100644
index 0000000..11ca4de
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingInboundConnection.java
@@ -0,0 +1,148 @@
+/*
+*
+ * 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.transport;
+
+import java.nio.channels.SocketChannel;
+import java.util.Set;
+
+import javax.net.ssl.SSLEngine;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.server.model.port.AmqpPort;
+import org.apache.qpid.transport.network.TransportEncryption;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
+
+public class NonBlockingInboundConnection extends NonBlockingConnection
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(NonBlockingInboundConnection.class);
+
+    private final Runnable _onTransportEncryptionAction;
+    private final long _outboundMessageBufferLimit;
+
+
+    private final AmqpPort _port;
+
+    public NonBlockingInboundConnection(SocketChannel socketChannel,
+                                        ProtocolEngine protocolEngine,
+                                        final Set<TransportEncryption> encryptionSet,
+                                        final Runnable onTransportEncryptionAction,
+                                        final NetworkConnectionScheduler scheduler,
+                                        final AmqpPort port)
+    {
+        super(socketChannel, protocolEngine, scheduler, socketChannel.socket().getRemoteSocketAddress().toString());
+        _onTransportEncryptionAction = onTransportEncryptionAction;
+
+        _port = port;
+
+        _outboundMessageBufferLimit = (long) _port.getContextValue(Long.class,
+                                                                   AmqpPort.PORT_AMQP_OUTBOUND_MESSAGE_BUFFER_SIZE);
+
+
+        if(encryptionSet.size() == 1)
+        {
+            setTransportEncryption(encryptionSet.iterator().next());
+        }
+        else
+        {
+            setDelegate(new NonBlockingConnectionUndecidedDelegate(this));
+        }
+
+    }
+
+    static SSLEngine createSSLEngine(AmqpPort<?> port)
+    {
+        SSLEngine sslEngine = port.getSSLContext().createSSLEngine();
+        sslEngine.setUseClientMode(false);
+        SSLUtil.updateEnabledTlsProtocols(sslEngine, port.getTlsProtocolWhiteList(), port.getTlsProtocolBlackList());
+        SSLUtil.updateEnabledCipherSuites(sslEngine, port.getTlsCipherSuiteWhiteList(), port.getTlsCipherSuiteBlackList());
+        if(port.getTlsCipherSuiteWhiteList() != null && !port.getTlsCipherSuiteWhiteList().isEmpty())
+        {
+            SSLUtil.useCipherOrderIfPossible(sslEngine);
+        }
+
+        if(port.getNeedClientAuth())
+        {
+            sslEngine.setNeedClientAuth(true);
+        }
+        else if(port.getWantClientAuth())
+        {
+            sslEngine.setWantClientAuth(true);
+        }
+        return sslEngine;
+    }
+
+    @Override
+    protected long getOutboundMessageBufferLimit()
+    {
+        return _outboundMessageBufferLimit;
+    }
+
+    @Override
+    protected int getNetworkBufferSize()
+    {
+        return _port.getNetworkBufferSize();
+    }
+
+    @Override
+    public boolean wantsConnect()
+    {
+        return false;
+    }
+
+
+    @Override
+    public String toString()
+    {
+        return "[InboundConnection " + getRemoteAddressString() + "]";
+    }
+
+    public void setTransportEncryption(TransportEncryption transportEncryption)
+    {
+        NonBlockingConnectionDelegate oldDelegate = getDelegate();
+        switch (transportEncryption)
+        {
+            case TLS:
+                _onTransportEncryptionAction.run();
+                setDelegate(new NonBlockingConnectionTLSDelegate(this,
+                                                                 _port.getNetworkBufferSize(),
+                                                                 createSSLEngine(_port)));
+                break;
+            case NONE:
+                setDelegate(new NonBlockingConnectionPlainDelegate(this, _port.getNetworkBufferSize()));
+                break;
+            default:
+                throw new IllegalArgumentException("unknown TransportEncryption " + transportEncryption);
+        }
+        if(oldDelegate != null)
+        {
+            QpidByteBuffer src = oldDelegate.getNetInputBuffer().duplicate();
+            src.flip();
+            getDelegate().getNetInputBuffer().put(src);
+            src.dispose();
+        }
+        LOGGER.debug("Identified transport encryption as " + transportEncryption);
+    }
+
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java
index ad1435b..77ed00f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingNetworkTransport.java
@@ -20,6 +20,8 @@
  */
 package org.apache.qpid.server.transport;
 
+import static org.apache.qpid.transport.ConnectionSettings.WILDCARD_ADDRESS;
+
 import java.io.IOException;
 import java.net.BindException;
 import java.net.InetSocketAddress;
@@ -30,16 +32,14 @@
 import java.util.EnumSet;
 import java.util.Set;
 
-import org.apache.qpid.server.model.port.AmqpPort;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.configuration.CommonProperties;
+import org.apache.qpid.server.model.port.AmqpPort;
 import org.apache.qpid.transport.TransportException;
 import org.apache.qpid.transport.network.TransportEncryption;
 
-import static org.apache.qpid.transport.ConnectionSettings.WILDCARD_ADDRESS;
-
 public class NonBlockingNetworkTransport
 {
 
@@ -156,10 +156,10 @@
 
 
                     NonBlockingConnection connection =
-                            new NonBlockingConnection(socketChannel,
-                                                      engine,
-                                                      _encryptionSet,
-                                                      new Runnable()
+                            new NonBlockingInboundConnection(socketChannel,
+                                                             engine,
+                                                             _encryptionSet,
+                                                             new Runnable()
                                                       {
 
                                                           @Override
@@ -168,8 +168,8 @@
                                                               engine.encryptedTransport();
                                                           }
                                                       },
-                                                      _scheduler,
-                                                      _port);
+                                                             _scheduler,
+                                                             _port);
 
                     engine.setNetworkConnection(connection);
 
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingOutboundConnection.java b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingOutboundConnection.java
new file mode 100644
index 0000000..117a01b
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/NonBlockingOutboundConnection.java
@@ -0,0 +1,198 @@
+/*
+ *
+ * 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.transport;
+
+import java.nio.channels.SocketChannel;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.server.federation.OutboundProtocolEngine;
+import org.apache.qpid.server.model.Container;
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.model.port.AmqpPort;
+import org.apache.qpid.server.plugin.OutboundProtocolEngineCreator;
+import org.apache.qpid.server.plugin.QpidServiceLoader;
+import org.apache.qpid.server.util.Action;
+import org.apache.qpid.server.virtualhost.AbstractVirtualHost;
+import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
+
+public class NonBlockingOutboundConnection extends NonBlockingConnection
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(NonBlockingOutboundConnection.class);
+
+    private final AbstractVirtualHost<?> _virtualHost;
+    private final RemoteHostAddress<?> _address;
+    private final int _networkBufferSize;
+    private final long _outboundMessageBufferLimit;
+    private volatile boolean _connected;
+
+    public NonBlockingOutboundConnection(SocketChannel socketChannel,
+                                         final RemoteHostAddress<?> address,
+                                         final NetworkConnectionScheduler networkConnectionScheduler,
+                                         final AbstractVirtualHost<?> virtualHost,
+                                         final Action<Boolean> onConnectionLoss)
+    {
+        super(socketChannel, createProtocolEngine(address, virtualHost), networkConnectionScheduler, address.getAddress()+":"+address.getPort());
+        OutboundProtocolEngine protocolEngine = (OutboundProtocolEngine) getProtocolEngine();
+        protocolEngine.setConnection(this);
+        protocolEngine.setOnClosedTask(onConnectionLoss);
+        _virtualHost = virtualHost;
+        _address = address;
+        _networkBufferSize = virtualHost.getAncestor(Container.class).getNetworkBufferSize();
+        _outboundMessageBufferLimit = (long) virtualHost.getContextValue(Long.class,
+                                                                   AmqpPort.PORT_AMQP_OUTBOUND_MESSAGE_BUFFER_SIZE);
+
+        final NonBlockingConnectionDelegate delegate;
+        switch(address.getTransport())
+        {
+            case TCP:
+                delegate = new NonBlockingConnectionPlainDelegate(this, getNetworkBufferSize());
+                break;
+            case SSL:
+                delegate = new NonBlockingConnectionTLSDelegate(this, getNetworkBufferSize(), createSSLEngine(address));
+                break;
+            default:
+                throw new IllegalArgumentException("Transport '"+address.getTransport()+"' is not supported");
+        }
+        setDelegate(delegate);
+    }
+
+    private static ProtocolEngine createProtocolEngine(final RemoteHostAddress<?> address, final AbstractVirtualHost<?> virtualHost)
+    {
+        for(OutboundProtocolEngineCreator engineCreator : (new QpidServiceLoader()).instancesOf(OutboundProtocolEngineCreator.class))
+        {
+            if(engineCreator.getVersion().equals(address.getProtocol()))
+            {
+                return engineCreator.newProtocolEngine(address, virtualHost);
+            }
+        }
+
+        return null;
+    }
+
+
+    @Override
+    protected long getOutboundMessageBufferLimit()
+    {
+        return _outboundMessageBufferLimit;
+    }
+
+    @Override
+    protected int getNetworkBufferSize()
+    {
+        return _networkBufferSize;
+    }
+
+
+    @Override
+    public boolean wantsConnect()
+    {
+        return !_connected && !(_connected = getSocketChannel().isConnected());
+    }
+
+    static SSLEngine createSSLEngine(RemoteHostAddress<?> address)
+    {
+        SSLEngine sslEngine = createSslContext(address).createSSLEngine();
+        sslEngine.setUseClientMode(true);
+        SSLUtil.updateEnabledTlsProtocols(sslEngine, address.getTlsProtocolWhiteList(), address.getTlsProtocolBlackList());
+        SSLUtil.updateEnabledCipherSuites(sslEngine, address.getTlsCipherSuiteWhiteList(), address.getTlsCipherSuiteBlackList());
+        if(address.getTlsCipherSuiteWhiteList() != null && !address.getTlsCipherSuiteWhiteList().isEmpty())
+        {
+            SSLUtil.useCipherOrderIfPossible(sslEngine);
+        }
+
+        return sslEngine;
+    }
+
+    private static SSLContext createSslContext(RemoteHostAddress<?> address)
+    {
+        KeyStore keyStore = address.getKeyStore();
+        Collection<TrustStore> trustStores = address.getTrustStores();
+
+        try
+        {
+            SSLContext sslContext = SSLUtil.tryGetSSLContext();
+
+            KeyManager[] keyManagers = keyStore.getKeyManagers();
+
+            TrustManager[] trustManagers;
+            if(trustStores == null || trustStores.isEmpty())
+            {
+                trustManagers = null;
+            }
+            else if(trustStores.size() == 1)
+            {
+                trustManagers = trustStores.iterator().next().getTrustManagers();
+            }
+            else
+            {
+                Collection<TrustManager> trustManagerList = new ArrayList<>();
+                final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager();
+
+                for(TrustStore ts : trustStores)
+                {
+                    TrustManager[] managers = ts.getTrustManagers();
+                    if(managers != null)
+                    {
+                        for(TrustManager manager : managers)
+                        {
+                            if(manager instanceof X509TrustManager)
+                            {
+                                mulTrustManager.addTrustManager((X509TrustManager)manager);
+                            }
+                            else
+                            {
+                                trustManagerList.add(manager);
+                            }
+                        }
+                    }
+                }
+                if(!mulTrustManager.isEmpty())
+                {
+                    trustManagerList.add(mulTrustManager);
+                }
+                trustManagers = trustManagerList.toArray(new TrustManager[trustManagerList.size()]);
+            }
+            sslContext.init(keyManagers, trustManagers, null);
+
+            return sslContext;
+
+        }
+        catch (GeneralSecurityException e)
+        {
+            throw new IllegalArgumentException("Unable to create SSLContext for key or trust store", e);
+        }
+    }
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/SchedulableConnection.java b/broker-core/src/main/java/org/apache/qpid/server/transport/SchedulableConnection.java
new file mode 100644
index 0000000..d95bb56
--- /dev/null
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/SchedulableConnection.java
@@ -0,0 +1,68 @@
+/*
+ *
+ * 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.transport;
+
+import java.io.IOException;
+import java.nio.channels.SocketChannel;
+import java.util.Collection;
+
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.transport.ByteBufferSender;
+import org.apache.qpid.transport.network.Ticker;
+
+public interface SchedulableConnection extends ServerNetworkConnection, ByteBufferSender
+{
+    String getThreadName();
+
+    boolean isPartialRead();
+
+    Ticker getTicker();
+
+    SocketChannel getSocketChannel();
+
+    boolean wantsRead();
+
+    boolean wantsWrite();
+
+    boolean wantsConnect();
+
+    boolean isStateChanged();
+
+    void doPreWork();
+
+    boolean doWork();
+
+    NetworkConnectionScheduler getScheduler();
+
+    boolean setScheduled();
+
+    void clearScheduled();
+
+    SelectorThread.SelectionTask getSelectionTask();
+
+    void setSelectionTask(SelectorThread.SelectionTask selectionTask);
+
+    void processAmqpData(QpidByteBuffer applicationData);
+
+    long writeToTransport(Collection<QpidByteBuffer> bufferArray) throws IOException;
+
+    void reportUnexpectedByteBufferSizeUsage();
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java b/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java
index 04ee506..157e15b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/SelectorThread.java
@@ -71,10 +71,10 @@
          * Queue of connections that are not currently scheduled and not registered with the selector.
          * These need to go back into the Selector.
          */
-        private final Queue<NonBlockingConnection> _unregisteredConnections = new ConcurrentLinkedQueue<>();
+        private final Queue<SchedulableConnection> _unregisteredConnections = new ConcurrentLinkedQueue<>();
 
         /** Set of connections that are currently being selected upon */
-        private final Set<NonBlockingConnection> _unscheduledConnections = new HashSet<>();
+        private final Set<SchedulableConnection> _unscheduledConnections = new HashSet<>();
 
 
 
@@ -104,17 +104,17 @@
             return _selector;
         }
 
-        public Queue<NonBlockingConnection> getUnregisteredConnections()
+        public Queue<SchedulableConnection> getUnregisteredConnections()
         {
             return _unregisteredConnections;
         }
 
-        public Set<NonBlockingConnection> getUnscheduledConnections()
+        public Set<SchedulableConnection> getUnscheduledConnections()
         {
             return _unscheduledConnections;
         }
 
-        private List<NonBlockingConnection> processUnscheduledConnections()
+        private List<SchedulableConnection> processUnscheduledConnections()
         {
             _nextTimeout = Integer.MAX_VALUE;
             if (getUnscheduledConnections().isEmpty())
@@ -122,13 +122,13 @@
                 return Collections.emptyList();
             }
 
-            List<NonBlockingConnection> toBeScheduled = new ArrayList<>();
+            List<SchedulableConnection> toBeScheduled = new ArrayList<>();
 
             long currentTime = System.currentTimeMillis();
-            Iterator<NonBlockingConnection> iterator = getUnscheduledConnections().iterator();
+            Iterator<SchedulableConnection> iterator = getUnscheduledConnections().iterator();
             while (iterator.hasNext())
             {
-                NonBlockingConnection connection = iterator.next();
+                SchedulableConnection connection = iterator.next();
 
                 int period = connection.getTicker().getTimeToNextTick(currentTime);
 
@@ -153,10 +153,10 @@
             }
 
             // QPID-7447: prevent unnecessary allocation of empty iterator
-            return toBeScheduled.isEmpty() ? Collections.<NonBlockingConnection>emptyList() : toBeScheduled;
+            return toBeScheduled.isEmpty() ? Collections.<SchedulableConnection>emptyList() : toBeScheduled;
         }
 
-        private List<NonBlockingConnection> processSelectionKeys()
+        private List<SchedulableConnection> processSelectionKeys()
         {
             Set<SelectionKey> selectionKeys = _selector.selectedKeys();
             if (selectionKeys.isEmpty())
@@ -164,7 +164,7 @@
                 return Collections.emptyList();
             }
 
-            List<NonBlockingConnection> toBeScheduled = new ArrayList<>();
+            List<SchedulableConnection> toBeScheduled = new ArrayList<>();
             for (SelectionKey key : selectionKeys)
             {
                 if(key.isAcceptable())
@@ -215,7 +215,7 @@
                 }
                 else
                 {
-                    NonBlockingConnection connection = (NonBlockingConnection) key.attachment();
+                    SchedulableConnection connection = (SchedulableConnection) key.attachment();
                     if(connection != null)
                     {
                         try
@@ -238,15 +238,15 @@
             return toBeScheduled;
         }
 
-        private List<NonBlockingConnection> reregisterUnregisteredConnections()
+        private List<SchedulableConnection> reregisterUnregisteredConnections()
         {
             if (getUnregisteredConnections().isEmpty())
             {
                 return Collections.emptyList();
             }
-            List<NonBlockingConnection> unregisterableConnections = new ArrayList<>();
+            List<SchedulableConnection> unregisterableConnections = new ArrayList<>();
 
-            NonBlockingConnection unregisteredConnection;
+            SchedulableConnection unregisteredConnection;
             while ((unregisteredConnection = getUnregisteredConnections().poll()) != null)
             {
                 getUnscheduledConnections().add(unregisteredConnection);
@@ -265,7 +265,7 @@
             }
 
             // QPID-7447: prevent unnecessary allocation of empty iterator
-            return unregisterableConnections.isEmpty() ? Collections.<NonBlockingConnection>emptyList() : unregisterableConnections;
+            return unregisterableConnections.isEmpty() ? Collections.<SchedulableConnection>emptyList() : unregisterableConnections;
         }
 
         private void performSelect()
@@ -306,21 +306,21 @@
                                 {
                                     _inSelect.set(false);
                                 }
-                                for (NonBlockingConnection connection : processSelectionKeys())
+                                for (SchedulableConnection connection : processSelectionKeys())
                                 {
                                     if (connection.setScheduled())
                                     {
                                         connections.add(new ConnectionProcessor(_scheduler, connection));
                                     }
                                 }
-                                for (NonBlockingConnection connection : reregisterUnregisteredConnections())
+                                for (SchedulableConnection connection : reregisterUnregisteredConnections())
                                 {
                                     if (connection.setScheduled())
                                     {
                                         connections.add(new ConnectionProcessor(_scheduler, connection));
                                     }
                                 }
-                                for (NonBlockingConnection connection : processUnscheduledConnections())
+                                for (SchedulableConnection connection : processUnscheduledConnections())
                                 {
                                     if (connection.setScheduled())
                                     {
@@ -501,10 +501,10 @@
     {
 
         private final NetworkConnectionScheduler _scheduler;
-        private final NonBlockingConnection _connection;
+        private final SchedulableConnection _connection;
         private AtomicBoolean _running = new AtomicBoolean();
 
-        public ConnectionProcessor(final NetworkConnectionScheduler scheduler, final NonBlockingConnection connection)
+        public ConnectionProcessor(final NetworkConnectionScheduler scheduler, final SchedulableConnection connection)
         {
             _scheduler = scheduler;
             _connection = connection;
@@ -533,7 +533,7 @@
         }
     }
 
-    private void unregisterConnection(final NonBlockingConnection connection) throws ClosedChannelException
+    private void unregisterConnection(final SchedulableConnection connection) throws ClosedChannelException
     {
         SelectionKey register = connection.getSocketChannel().register(connection.getSelectionTask().getSelector(), 0);
         register.cancel();
@@ -548,14 +548,15 @@
         }
     }
 
-    private boolean selectionInterestRequiresUpdate(NonBlockingConnection connection)
+    private boolean selectionInterestRequiresUpdate(SchedulableConnection connection)
     {
         SelectionTask selectionTask = connection.getSelectionTask();
         if(selectionTask != null)
         {
             final SelectionKey selectionKey = connection.getSocketChannel().keyFor(selectionTask.getSelector());
             int expectedOps = (connection.wantsRead() ? SelectionKey.OP_READ : 0)
-                              | (connection.wantsWrite() ? SelectionKey.OP_WRITE : 0);
+                              | (connection.wantsWrite() ? SelectionKey.OP_WRITE : 0)
+                              | (connection.wantsConnect() ? SelectionKey.OP_CONNECT : 0);
 
             try
             {
@@ -572,7 +573,7 @@
         }
     }
 
-    public void addConnection(final NonBlockingConnection connection)
+    public void addConnection(final SchedulableConnection connection)
     {
         if(selectionInterestRequiresUpdate(connection))
         {
@@ -584,7 +585,7 @@
 
     }
 
-    public void returnConnectionToSelector(final NonBlockingConnection connection)
+    public void returnConnectionToSelector(final SchedulableConnection connection)
     {
         if(selectionInterestRequiresUpdate(connection))
         {
@@ -610,7 +611,7 @@
         return _selectionTasks[index];
     }
 
-    void removeConnection(NonBlockingConnection connection)
+    void removeConnection(SchedulableConnection connection)
     {
         try
         {
@@ -658,7 +659,7 @@
 
     }
 
-     public void addToWork(final NonBlockingConnection connection)
+     public void addToWork(final SchedulableConnection connection)
      {
          if (_closed.get())
          {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractSystemMessageSource.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractSystemMessageSource.java
index 4a69f00..935ab60 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractSystemMessageSource.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractSystemMessageSource.java
@@ -29,12 +29,14 @@
 import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.FilterManager;
 import org.apache.qpid.server.filter.Filterable;
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.message.internal.InternalMessage;
@@ -48,12 +50,12 @@
 import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.util.StateChangeListener;
 
-public abstract class AbstractSystemMessageSource implements MessageSource
+public abstract class AbstractSystemMessageSource implements MessageSource<AbstractSystemMessageSource.SystemMessageSourceConsumer>
 {
-    protected final UUID _id;
-    protected final String _name;
-    protected final NamedAddressSpace _addressSpace;
-    private List<Consumer> _consumers = new CopyOnWriteArrayList<>();
+    private final UUID _id;
+    private final String _name;
+    private final NamedAddressSpace _addressSpace;
+    private List<SystemMessageSourceConsumer> _consumers = new CopyOnWriteArrayList<>();
 
     public AbstractSystemMessageSource(String name, final NamedAddressSpace addressSpace)
     {
@@ -82,22 +84,22 @@
     }
 
     @Override
-    public Consumer addConsumer(final ConsumerTarget target,
-                                final FilterManager filters,
-                                final Class<? extends ServerMessage> messageClass,
-                                final String consumerName,
-                                final EnumSet<ConsumerImpl.Option> options, final Integer priority)
+    public SystemMessageSourceConsumer addConsumer(final ConsumerTarget target,
+                                                   final FilterManager filters,
+                                                   final Class<? extends ServerMessage> messageClass,
+                                                   final String consumerName,
+                                                   final EnumSet<ConsumerOption> options, final Integer priority)
             throws ExistingExclusiveConsumer, ExistingConsumerPreventsExclusive,
                    ConsumerAccessRefused
     {
-        final Consumer consumer = new Consumer(consumerName, target);
+        final SystemMessageSourceConsumer consumer = new SystemMessageSourceConsumer(consumerName, target);
         target.consumerAdded(consumer);
         _consumers.add(consumer);
         return consumer;
     }
 
     @Override
-    public Collection<Consumer> getConsumers()
+    public Collection<SystemMessageSourceConsumer> getConsumers()
     {
         return new ArrayList<>(_consumers);
     }
@@ -108,19 +110,23 @@
         return true;
     }
 
-    protected class Consumer implements ConsumerImpl
+    public NamedAddressSpace getAddressSpace()
+    {
+        return _addressSpace;
+    }
+
+    protected class SystemMessageSourceConsumer implements MessageInstanceConsumer
     {
 
-        private final long _id = ConsumerImpl.CONSUMER_NUMBER_GENERATOR.getAndIncrement();
         private final List<PropertiesMessageInstance> _queue =
                 Collections.synchronizedList(new ArrayList<PropertiesMessageInstance>());
         private final ConsumerTarget _target;
         private final String _name;
         private final StateChangeListener<ConsumerTarget, ConsumerTarget.State> _targetChangeListener =
-                new Consumer.TargetChangeListener();
+                new SystemMessageSourceConsumer.TargetChangeListener();
+        private final Object _identifier = new Object();
 
-
-        public Consumer(final String consumerName, ConsumerTarget target)
+        SystemMessageSourceConsumer(final String consumerName, ConsumerTarget target)
         {
             _name = consumerName;
             _target = target;
@@ -133,13 +139,16 @@
 
         }
 
-        @Override
+        public Object getIdentifier()
+        {
+            return _identifier;
+        }
+
         public ConsumerTarget getTarget()
         {
             return _target;
         }
 
-        @Override
         public boolean hasAvailableMessages()
         {
             return !_queue.isEmpty();
@@ -151,55 +160,12 @@
 
         }
 
-        @Override
-        public long getBytesOut()
-        {
-            return 0;
-        }
-
-        @Override
-        public long getMessagesOut()
-        {
-            return 0;
-        }
-
-        @Override
-        public long getUnacknowledgedBytes()
-        {
-            return 0;
-        }
-
-        @Override
-        public long getUnacknowledgedMessages()
-        {
-            return 0;
-        }
-
-        @Override
         public AMQSessionModel getSessionModel()
         {
             return _target.getSessionModel();
         }
 
         @Override
-        public MessageSource getMessageSource()
-        {
-            return AbstractSystemMessageSource.this;
-        }
-
-        @Override
-        public long getConsumerNumber()
-        {
-            return _id;
-        }
-
-        @Override
-        public boolean isSuspended()
-        {
-            return false;
-        }
-
-        @Override
         public boolean isClosed()
         {
             return false;
@@ -212,42 +178,12 @@
         }
 
         @Override
-        public boolean seesRequeues()
-        {
-            return false;
-        }
-
-        @Override
         public void close()
         {
             _consumers.remove(this);
         }
 
         @Override
-        public boolean trySendLock()
-        {
-            return _target.trySendLock();
-        }
-
-        @Override
-        public void getSendLock()
-        {
-            _target.getSendLock();
-        }
-
-        @Override
-        public void releaseSendLock()
-        {
-            _target.releaseSendLock();
-        }
-
-        @Override
-        public boolean isActive()
-        {
-            return false;
-        }
-
-        @Override
         public String getName()
         {
             return _name;
@@ -334,16 +270,15 @@
 
     }
 
-    class PropertiesMessageInstance implements MessageInstance
+    private class PropertiesMessageInstance implements MessageInstance
     {
-        private final Consumer _consumer;
+        private final SystemMessageSourceConsumer _consumer;
         private int _deliveryCount;
         private boolean _isRedelivered;
-        private boolean _isDelivered;
         private boolean _isDeleted;
         private InternalMessage _message;
 
-        PropertiesMessageInstance(final Consumer consumer, final InternalMessage message)
+        PropertiesMessageInstance(final SystemMessageSourceConsumer consumer, final InternalMessage message)
         {
             _consumer = consumer;
             _message = message;
@@ -352,7 +287,7 @@
         @Override
         public int getDeliveryCount()
         {
-            return 0;
+            return _deliveryCount;
         }
 
         @Override
@@ -387,7 +322,7 @@
         }
 
         @Override
-        public ConsumerImpl getAcquiringConsumer()
+        public MessageInstanceConsumer getAcquiringConsumer()
         {
             return _consumer;
         }
@@ -399,13 +334,13 @@
         }
 
         @Override
-        public boolean isAcquiredBy(final ConsumerImpl consumer)
+        public boolean isAcquiredBy(final MessageInstanceConsumer consumer)
         {
             return consumer == _consumer && !isDeleted();
         }
 
         @Override
-        public boolean removeAcquisitionFromConsumer(final ConsumerImpl consumer)
+        public boolean removeAcquisitionFromConsumer(final MessageInstanceConsumer consumer)
         {
             return consumer == _consumer;
         }
@@ -423,7 +358,7 @@
         }
 
         @Override
-        public Consumer getDeliveredConsumer()
+        public SystemMessageSourceConsumer getDeliveredConsumer()
         {
             return isDeleted() ? null : _consumer;
         }
@@ -435,7 +370,7 @@
         }
 
         @Override
-        public boolean isRejectedBy(final ConsumerImpl consumer)
+        public boolean isRejectedBy(final MessageInstanceConsumer consumer)
         {
             return false;
         }
@@ -443,7 +378,7 @@
         @Override
         public boolean getDeliveredToConsumer()
         {
-            return _isDelivered;
+            return _deliveryCount > 0;
         }
 
         @Override
@@ -453,13 +388,13 @@
         }
 
         @Override
-        public boolean acquire(final ConsumerImpl sub)
+        public boolean acquire(final MessageInstanceConsumer sub)
         {
             return false;
         }
 
         @Override
-        public boolean makeAcquisitionUnstealable(final ConsumerImpl consumer)
+        public boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer)
         {
             return false;
         }
@@ -477,7 +412,7 @@
         }
 
         @Override
-        public int routeToAlternate(final Action<? super MessageInstance> action,
+        public int routeToAlternate(final Action<? super BaseMessageInstance> action,
                                     final ServerTransaction txn)
         {
             return 0;
@@ -515,7 +450,7 @@
         }
 
         @Override
-        public void release(ConsumerImpl consumer)
+        public void release(MessageInstanceConsumer consumer)
         {
             release();
         }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
index bc072f2..5b9c3ac 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java
@@ -30,9 +30,11 @@
 import java.io.OutputStream;
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLEncoder;
+import java.nio.channels.SocketChannel;
 import java.nio.charset.StandardCharsets;
 import java.security.AccessControlContext;
 import java.security.Principal;
@@ -132,8 +134,11 @@
 import org.apache.qpid.server.store.preferences.PreferencesRecoverer;
 import org.apache.qpid.server.store.preferences.PreferencesRoot;
 import org.apache.qpid.server.store.serializer.MessageStoreSerializer;
+import org.apache.qpid.server.transfer.TransferQueue;
+import org.apache.qpid.server.transfer.TransferQueueImpl;
 import org.apache.qpid.server.transport.AMQPConnection;
 import org.apache.qpid.server.transport.NetworkConnectionScheduler;
+import org.apache.qpid.server.transport.NonBlockingOutboundConnection;
 import org.apache.qpid.server.txn.AutoCommitTransaction;
 import org.apache.qpid.server.txn.DtxRegistry;
 import org.apache.qpid.server.txn.LocalTransaction;
@@ -155,6 +160,9 @@
     private final AtomicBoolean _acceptsConnections = new AtomicBoolean(false);
     private TaskExecutor _preferenceTaskExecutor;
 
+    private Map<String,MessageDestination> _availableRoutes = new HashMap<>();
+    private TransferQueue _transferQueue;
+
     private static enum BlockingType { STORE, FILESYSTEM };
 
     private static final String USE_ASYNC_RECOVERY = "use_async_message_store_recovery";
@@ -216,7 +224,6 @@
         }
     }, Result.DEFER);
 
-
     @ManagedAttributeField
     private boolean _queue_deadLetterQueueEnabled;
 
@@ -304,6 +311,7 @@
         _fileSystemSpaceCheckerJobContext = getSystemTaskControllerContext("FileSystemSpaceChecker["+getName()+"]", _principal);
 
         _fileSystemSpaceChecker = new FileSystemSpaceChecker();
+        _transferQueue = new TransferQueueImpl(this);
 
         addChangeListener(new TargetSizeAssigningListener());
     }
@@ -438,6 +446,13 @@
     {
         super.postResolveChildren();
         addChangeListener(_accessControlProviderListener);
+        for(RemoteHost<?> remoteHost : getChildren(RemoteHost.class))
+        {
+            for(String address : remoteHost.getRoutableAddresses())
+            {
+                _availableRoutes.put(address, _transferQueue);
+            }
+        }
     }
 
     private void validateNodeAutoCreationPolicy(final NodeAutoCreationPolicy policy)
@@ -793,7 +808,9 @@
         {
             throw new UnsupportedOperationException();
         }
-        else if(childClass == VirtualHostLogger.class || childClass == VirtualHostAccessControlProvider.class)
+        else if(childClass == VirtualHostLogger.class
+                || childClass == VirtualHostAccessControlProvider.class
+                || childClass == RemoteHost.class)
         {
             return getObjectFactory().createAsync(childClass, attributes, this);
         }
@@ -1333,12 +1350,60 @@
         }
         if(destination == null)
         {
-
             destination = autoCreateNode(name, MessageDestination.class, true);
         }
+        if(destination == null)
+        {
+            destination = getTransferAgent( name );
+        }
         return destination;
     }
 
+    private MessageDestination getTransferAgent(final String address)
+    {
+        if(address.contains("/") && getGlobalAddressDomains() != null)
+        {
+            for(String domain : getGlobalAddressDomains())
+            {
+                if(address.startsWith(domain + "/"))
+                {
+                    return null;
+                }
+            }
+        }
+        for(Map.Entry<String, MessageDestination> route : _availableRoutes.entrySet())
+        {
+            if(address.equals(route.getKey()) || address.startsWith(route.getKey() + "/"))
+            {
+                return route.getValue();
+            }
+        }
+        return null;
+    }
+
+    private boolean isGlobalAddress(final String address)
+    {
+        if(address.contains("/") && getGlobalAddressDomains() != null)
+        {
+            for(String domain : getGlobalAddressDomains())
+            {
+                if(address.startsWith(domain + "/"))
+                {
+                    return false;
+                }
+            }
+        }
+        Set<String> routes = _availableRoutes.keySet();
+        for(String route : routes)
+        {
+            if(address.equals(route) || address.startsWith(address + "/"))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public <T extends ConfiguredObject<?>> T getAttainedChildFromAddress(final Class<T> childClass,
                                                                          final String address)
@@ -1410,7 +1475,7 @@
             {
                 if(localAddress.length() > routingAddress.length() - domain.length() && routingAddress.startsWith(domain + "/"))
                 {
-                    localAddress = routingAddress.substring(domain.length());
+                    localAddress = routingAddress.substring(domain.length()+1);
                 }
             }
         }
@@ -1752,7 +1817,7 @@
         }
     }
 
-    private class TargetSizeAssigningListener implements ConfigurationChangeListener
+    private class TargetSizeAssigningListener extends AbstractConfigurationChangeListener
     {
         @Override
         public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
@@ -1780,23 +1845,6 @@
         {
         }
 
-        @Override
-        public void attributeSet(final ConfiguredObject<?> object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-        }
     }
 
     private class VirtualHostHouseKeepingTask extends HouseKeepingTask
@@ -2559,6 +2607,29 @@
         }
     }
 
+    public boolean makeConnection(final RemoteHostAddress<?> address, final Action<Boolean> onConnectionLoss)
+    {
+        try
+        {
+
+            _logger.info("Attempting to connect to {}", address);
+            SocketChannel socketChannel = SocketChannel.open();
+            socketChannel.configureBlocking(false);
+            socketChannel.connect(new InetSocketAddress(address.getAddress(), address.getPort()));
+            NonBlockingOutboundConnection connection = new NonBlockingOutboundConnection(socketChannel,
+                                                                                         address,
+                                                                                         _networkConnectionScheduler,
+                                                                                         this, onConnectionLoss);
+            _networkConnectionScheduler.addConnection(connection);
+            return true;
+        }
+        catch (IOException e)
+        {
+            _logger.debug("Failed to make connection to {}", address, e);
+            return false;
+        }
+    }
+
     protected void startFileSystemSpaceChecking()
     {
         File storeLocationAsFile = _messageStore.getStoreLocationAsFile();
@@ -2702,6 +2773,12 @@
     }
 
     @Override
+    public TransferQueue getTransferQueue()
+    {
+        return _transferQueue;
+    }
+
+    @Override
     public <T extends MessageDestination> T createMessageDestination(final Class<T> clazz,
                                                                      final Map<String, Object> attributes)
     {
@@ -2725,17 +2802,11 @@
         return !(_systemNodeSources.isEmpty() && getChildren(Queue.class).isEmpty());
     }
 
-    private final class AccessControlProviderListener implements ConfigurationChangeListener
+    private final class AccessControlProviderListener extends AbstractConfigurationChangeListener
     {
         private final Set<ConfiguredObject<?>> _bulkChanges = new HashSet<>();
 
         @Override
-        public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
-        {
-
-        }
-
-        @Override
         public void childAdded(final ConfiguredObject<?> object, final ConfiguredObject<?> child)
         {
             if(object.getCategoryClass() == VirtualHost.class && child.getCategoryClass() == VirtualHostAccessControlProvider.class)
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecoverer.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecoverer.java
index b1617b2..84b8774 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecoverer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecoverer.java
@@ -48,6 +48,7 @@
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.plugin.MessageMetaDataType;
 import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.RecoverableBaseQueue;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.store.StorableMessageMetaData;
@@ -127,6 +128,9 @@
                 ListenableFuture<Void> result = _queueRecoveryExecutor.submit(new QueueRecoveringTask(queue), null);
                 queueRecoveryFutures.add(result);
             }
+            ListenableFuture<Void> result = _queueRecoveryExecutor.submit(new QueueRecoveringTask(_virtualHost.getTransferQueue()), null);
+            queueRecoveryFutures.add(result);
+
             ListenableFuture<List<Void>> combinedFuture = Futures.allAsList(queueRecoveryFutures);
             return Futures.transform(combinedFuture, new Function<List<?>, Void>()
             {
@@ -163,7 +167,7 @@
             return _recoveringQueues.contains(queue);
         }
 
-        private void recoverQueue(Queue<?> queue)
+        private void recoverQueue(RecoverableBaseQueue queue)
         {
             MessageInstanceVisitor handler = new MessageInstanceVisitor(queue);
             _storeReader.visitMessageInstances(queue, handler);
@@ -434,9 +438,9 @@
 
         private class QueueRecoveringTask implements Runnable
         {
-            private final Queue<?> _queue;
+            private final RecoverableBaseQueue _queue;
 
-            public QueueRecoveringTask(final Queue<?> queue)
+            public QueueRecoveringTask(final RecoverableBaseQueue queue)
             {
                 _queue = queue;
             }
@@ -461,10 +465,10 @@
 
         private class MessageInstanceVisitor implements MessageInstanceHandler
         {
-            private final Queue<?> _queue;
+            private final RecoverableBaseQueue _queue;
             long _recoveredCount;
 
-            private MessageInstanceVisitor(Queue<?> queue)
+            private MessageInstanceVisitor(RecoverableBaseQueue queue)
             {
                 _queue = queue;
             }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecoverer.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecoverer.java
index f67935d..6f3c94a 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecoverer.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecoverer.java
@@ -40,6 +40,7 @@
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.plugin.MessageMetaDataType;
 import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.server.queue.RecoverableBaseQueue;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.store.StorableMessageMetaData;
@@ -49,6 +50,7 @@
 import org.apache.qpid.server.store.handler.DistributedTransactionHandler;
 import org.apache.qpid.server.store.handler.MessageHandler;
 import org.apache.qpid.server.store.handler.MessageInstanceHandler;
+import org.apache.qpid.server.transfer.TransferQueue;
 import org.apache.qpid.server.txn.DtxBranch;
 import org.apache.qpid.server.txn.DtxRegistry;
 import org.apache.qpid.server.txn.ServerTransaction;
@@ -85,7 +87,11 @@
         {
             eventLogger.message(logSubject, TransactionLogMessages.RECOVERED(entry.getValue(), entry.getKey()));
             eventLogger.message(logSubject, TransactionLogMessages.RECOVERY_COMPLETE(entry.getKey(), true));
-            virtualHost.getAttainedChildFromAddress(Queue.class, entry.getKey()).completeRecovery();
+            Queue queue = virtualHost.getAttainedChildFromAddress(Queue.class, entry.getKey());
+            if(queue != null)
+            {
+                queue.completeRecovery();
+            }
         }
 
         for(Queue<?> q : virtualHost.getChildren(Queue.class))
@@ -95,6 +101,8 @@
                 q.completeRecovery();
             }
         }
+        TransferQueue q = virtualHost.getTransferQueue();
+        q.completeRecovery();
 
         storeReader.visitDistributedTransactions(new DistributedTransactionVisitor(virtualHost, store, eventLogger,
                                                                              logSubject, recoveredMessages, unusedMessages));
@@ -179,7 +187,11 @@
         {
             final UUID queueId = record.getQueueId();
             long messageId = record.getMessageNumber();
-            Queue<?> queue = _virtualHost.getAttainedQueue(queueId);
+            RecoverableBaseQueue queue = _virtualHost.getAttainedQueue(queueId);
+            if(queue == null && _virtualHost.getTransferQueue().getId().equals(queueId))
+            {
+                queue = _virtualHost.getTransferQueue();
+            }
             if(queue != null)
             {
                 String queueName = queue.getName();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNode.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNode.java
index 8392ce4..81b8232 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNode.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNode.java
@@ -26,9 +26,9 @@
 import java.util.Map;
 import java.util.UUID;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.FilterManager;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.message.internal.InternalMessage;
 import org.apache.qpid.server.message.internal.InternalMessageHeader;
@@ -47,15 +47,16 @@
     }
 
     @Override
-    public Consumer addConsumer(final ConsumerTarget target,
-                                final FilterManager filters,
-                                final Class<? extends ServerMessage> messageClass,
-                                final String consumerName,
-                                final EnumSet<ConsumerImpl.Option> options, final Integer priority)
+    public SystemMessageSourceConsumer addConsumer(final ConsumerTarget target,
+                                                   final FilterManager filters,
+                                                   final Class<? extends ServerMessage> messageClass,
+                                                   final String consumerName,
+                                                   final EnumSet<ConsumerOption> options, final Integer priority)
             throws ExistingExclusiveConsumer, ExistingConsumerPreventsExclusive,
                    ConsumerAccessRefused
     {
-        final Consumer consumer = super.addConsumer(target, filters, messageClass, consumerName, options, priority);
+        final SystemMessageSourceConsumer
+                consumer = super.addConsumer(target, filters, messageClass, consumerName, options, priority);
         consumer.send(createMessage());
         target.queueEmpty();
         return consumer;
@@ -66,7 +67,7 @@
 
         Map<String, Object> headers = new HashMap<>();
 
-        final List<String> globalAddresseDomains = _addressSpace.getGlobalAddressDomains();
+        final List<String> globalAddresseDomains = getAddressSpace().getGlobalAddressDomains();
         if (globalAddresseDomains != null && !globalAddresseDomains.isEmpty())
         {
             String primaryDomain = globalAddresseDomains.get(0);
@@ -80,13 +81,13 @@
                 headers.put("virtualHost.temporaryQueuePrefix", primaryDomain);
             }
         }
-
+        headers.put("virtualhost.globalDomains", globalAddresseDomains);
         InternalMessageHeader header = new InternalMessageHeader(headers,
                                                                  null, 0l, null, null, UUID.randomUUID().toString(),
                                                                  null, null, (byte) 4, System.currentTimeMillis(),
                                                                  0L, null, null);
         final InternalMessage message =
-                InternalMessage.createBytesMessage(_addressSpace.getMessageStore(), header, new byte[0]);
+                InternalMessage.createBytesMessage(getAddressSpace().getMessageStore(), header, new byte[0]);
         message.setInitialRoutingAddress(getName());
         return message;
     }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java b/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
index 289287f..fc51d42 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/virtualhostnode/RedirectingVirtualHostImpl.java
@@ -47,6 +47,7 @@
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
 import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.RemoteHostAddress;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.VirtualHostNode;
 import org.apache.qpid.server.model.port.AmqpPort;
@@ -55,8 +56,10 @@
 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.transfer.TransferQueue;
 import org.apache.qpid.server.transport.AMQPConnection;
 import org.apache.qpid.server.txn.DtxRegistry;
+import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.virtualhost.HouseKeepingTask;
 import org.apache.qpid.server.virtualhost.NodeAutoCreationPolicy;
 import org.apache.qpid.server.virtualhost.VirtualHostPrincipal;
@@ -524,6 +527,12 @@
     }
 
     @Override
+    public TransferQueue getTransferQueue()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public Principal getPrincipal()
     {
         return _principal;
@@ -554,6 +563,13 @@
     }
 
     @Override
+    public boolean makeConnection(final RemoteHostAddress<?> address, final Action<Boolean> onConnectionLoss)
+    {
+        throwUnsupportedForRedirector();
+        return false;
+    }
+
+    @Override
     public UserPreferences createUserPreferences(final ConfiguredObject<?> object)
     {
         throwUnsupportedForRedirector();
diff --git a/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java b/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java
index 50ade31..5cec366 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/consumer/MockConsumer.java
@@ -36,6 +36,7 @@
 import org.apache.qpid.server.configuration.updater.TaskExecutor;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.BrokerModel;
 import org.apache.qpid.server.model.ConfiguredObjectFactory;
@@ -136,7 +137,7 @@
     {
     }
 
-    public long send(final ConsumerImpl consumer, MessageInstance entry, boolean batch)
+    public long send(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
     {
         long size = entry.getMessage().getSize();
         if (messages.contains(entry))
@@ -188,12 +189,12 @@
     }
 
     @Override
-    public void consumerAdded(final ConsumerImpl sub)
+    public void consumerAdded(final MessageInstanceConsumer consumer)
     {
     }
 
     @Override
-    public void consumerRemoved(final ConsumerImpl sub)
+    public void consumerRemoved(final MessageInstanceConsumer consumer)
     {
        close();
     }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/ConfiguredObjectTypeRegistryTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/ConfiguredObjectTypeRegistryTest.java
index fab9944..cc83945 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/ConfiguredObjectTypeRegistryTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/ConfiguredObjectTypeRegistryTest.java
@@ -98,7 +98,8 @@
                 (ConfiguredObjectOperation<TestCar>) kitCarOperations.get("openDoor");
 
         // test explicitly setting parameter
-        Object returnVal = operation.perform(object, Collections.<String, Object>singletonMap("door", "DRIVER"));
+        Object returnVal = operation.perform(object, Collections.<String, Object>singletonMap("door", "DRIVER")
+                                            );
         assertEquals(TestCar.Door.DRIVER, returnVal);
 
         // test default parameter
@@ -117,7 +118,8 @@
 
         try
         {
-            operation.perform(object, Collections.<String, Object>singletonMap("door", "[\"eggs\", \"flour\", \"milk\"]"));
+            operation.perform(object, Collections.<String, Object>singletonMap("door", "[\"eggs\", \"flour\", \"milk\"]")
+                             );
             fail("Should not be able to pass in a parameter of the wrong type");
         }
         catch(IllegalArgumentException e)
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
index 1c69983..85503ae 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/hierarchy/InjectedAttributeTest.java
@@ -385,11 +385,13 @@
 
         final ConfiguredObjectOperation foundOperation = allOperations.get("fly");
 
-        Object result = foundOperation.perform(testCar, Collections.<String, Object>singletonMap("height", 0));
+        Object result = foundOperation.perform(testCar, Collections.<String, Object>singletonMap("height", 0)
+                                              );
 
         assertEquals("Car should be able to fly at 0m", Boolean.TRUE, result);
 
-        result = foundOperation.perform(testCar, Collections.<String, Object>singletonMap("height", 5000));
+        result = foundOperation.perform(testCar, Collections.<String, Object>singletonMap("height", 5000)
+                                       );
 
         assertEquals("Car should not be able to fly at 5000m", Boolean.FALSE, result);
     }
@@ -436,11 +438,13 @@
         final ConfiguredObjectOperation helloOperation = allOperations.get("sayHello");
         final ConfiguredObjectOperation goodbyeOperation = allOperations.get("sayGoodbye");
 
-        Object result = helloOperation.perform(testCar, Collections.<String, Object>singletonMap("count", 3));
+        Object result = helloOperation.perform(testCar, Collections.<String, Object>singletonMap("count", 3)
+                                              );
 
         assertEquals("Car should say 'Hello' 3 times", Arrays.asList("Hello", "Hello", "Hello"), result);
 
-        result = goodbyeOperation.perform(testCar, Collections.<String, Object>singletonMap("count", 1));
+        result = goodbyeOperation.perform(testCar, Collections.<String, Object>singletonMap("count", 1)
+                                         );
 
         assertEquals("Car say 'Goodbye' once", Collections.singletonList("Goodbye"), result);
     }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/lifecycle/AbstractConfiguredObjectTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/lifecycle/AbstractConfiguredObjectTest.java
index a63fb82..4a95c40 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/lifecycle/AbstractConfiguredObjectTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/lifecycle/AbstractConfiguredObjectTest.java
@@ -30,7 +30,7 @@
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.IllegalStateTransitionException;
-import org.apache.qpid.server.model.NoopConfigurationChangeListener;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.Port;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.test.utils.QpidTestCase;
@@ -231,7 +231,7 @@
 
         final AtomicReference<State> newState = new AtomicReference<>();
         final AtomicInteger callCounter = new AtomicInteger();
-        parent.addChangeListener(new NoopConfigurationChangeListener()
+        parent.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(final ConfiguredObject<?> object, final State old, final State state)
@@ -262,7 +262,7 @@
         parent.create();
 
         final AtomicInteger callCounter = new AtomicInteger();
-        parent.addChangeListener(new NoopConfigurationChangeListener()
+        parent.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void stateChanged(final ConfiguredObject<?> object, final State old, final State state)
@@ -300,7 +300,7 @@
         configuredObject.create();
 
         final List<ChangeEvent> events = new ArrayList<>();
-        configuredObject.addChangeListener(new NoopConfigurationChangeListener()
+        configuredObject.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void attributeSet(ConfiguredObject<?> object, String attributeName, Object oldAttributeValue, Object newAttributeValue)
diff --git a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java
index 321d585..5ebf24a 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/model/testmodels/singleton/AbstractConfiguredObjectTest.java
@@ -37,7 +37,7 @@
 import org.apache.qpid.server.model.AbstractConfiguredObject;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.Model;
-import org.apache.qpid.server.model.NoopConfigurationChangeListener;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.SystemConfig;
 import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
 import org.apache.qpid.server.security.auth.UsernamePrincipal;
@@ -789,7 +789,7 @@
 
         final AtomicInteger listenerCount = new AtomicInteger();
         final LinkedHashMap<String, String> updates = new LinkedHashMap<>();
-        object.addChangeListener(new NoopConfigurationChangeListener()
+        object.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void attributeSet(final ConfiguredObject<?> object,
@@ -844,7 +844,7 @@
         final TestSingleton object = _model.getObjectFactory().create(TestSingleton.class, attributes);
 
         final AtomicInteger listenerCount = new AtomicInteger();
-        object.addChangeListener(new NoopConfigurationChangeListener()
+        object.addChangeListener(new AbstractConfigurationChangeListener()
         {
             @Override
             public void attributeSet(final ConfiguredObject<?> object,
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/AbstractQueueTestBase.java b/broker-core/src/test/java/org/apache/qpid/server/queue/AbstractQueueTestBase.java
index f53ea8f..fffdea6 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/AbstractQueueTestBase.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/AbstractQueueTestBase.java
@@ -40,10 +40,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.qpid.server.model.Binding;
-import org.apache.qpid.server.model.Exchange;
-import org.apache.qpid.server.model.VirtualHost;
-import org.apache.qpid.server.util.StateChangeListener;
 import org.mockito.ArgumentCaptor;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -51,21 +47,27 @@
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.exchange.ExchangeDefaults;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.MockConsumer;
 import org.apache.qpid.server.exchange.DirectExchange;
 import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.Binding;
+import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.Queue;
 import org.apache.qpid.server.model.QueueNotificationListener;
+import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.queue.AbstractQueue.QueueEntryFilter;
 import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.server.util.Action;
-import org.apache.qpid.server.model.BrokerTestHelper;
+import org.apache.qpid.server.util.StateChangeListener;
 import org.apache.qpid.test.utils.QpidTestCase;
 
 abstract class AbstractQueueTestBase extends QpidTestCase
@@ -173,8 +175,8 @@
 
         // Check adding a consumer adds it to the queue
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                  ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
         assertEquals("Queue does not have consumer", 1,
                      _queue.getConsumerCount());
         assertEquals("Queue does not have active consumer", 1,
@@ -205,8 +207,8 @@
         ServerMessage messageA = createMessage(new Long(24));
         _queue.enqueue(messageA, null, null);
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                  ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
         Thread.sleep(_queueRunnerWaitTime);
         assertEquals(messageA, _consumer.getQueueContext().getLastSeenEntry().getMessage());
         assertNull("There should be no releasedEntry after an enqueue",
@@ -223,8 +225,8 @@
         _queue.enqueue(messageA, null, null);
         _queue.enqueue(messageB, null, null);
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                  ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
         Thread.sleep(_queueRunnerWaitTime);
         assertEquals(messageB, _consumer.getQueueContext().getLastSeenEntry().getMessage());
         assertNull("There should be no releasedEntry after enqueues",
@@ -246,8 +248,8 @@
         when(messageHeader.getNotValidBefore()).thenReturn(System.currentTimeMillis()+20000L);
         _queue.enqueue(messageA, null, null);
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                                     ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
         Thread.sleep(_queueRunnerWaitTime);
 
         assertEquals("Message which was not yet valid was received", 0, _consumerTarget.getMessages().size());
@@ -272,8 +274,8 @@
         when(messageHeader.getNotValidBefore()).thenReturn(System.currentTimeMillis()+20000L);
         _queue.enqueue(messageA, null, null);
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                                     ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
         Thread.sleep(_queueRunnerWaitTime);
 
         assertEquals("Message was held despite queue not having holding enabled", 1, _consumerTarget.getMessages().size());
@@ -298,8 +300,8 @@
         _queue.enqueue(messageB, null, null);
 
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                                     ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
         Thread.sleep(_queueRunnerWaitTime);
 
         assertEquals("Expect one message (message B)", 1, _consumerTarget.getMessages().size());
@@ -326,8 +328,8 @@
 
 
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                      ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
 
         final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
         EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries);
@@ -375,7 +377,7 @@
         _consumerTarget = new MockConsumer()
         {
             @Override
-            public long send(ConsumerImpl consumer, MessageInstance entry, boolean batch)
+            public long send(MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
             {
                 try
                 {
@@ -389,8 +391,8 @@
         };
 
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.SEES_REQUEUES,
-                                                      ConsumerImpl.Option.ACQUIRES), 0);
+                                                          EnumSet.of(ConsumerOption.SEES_REQUEUES,
+                                                                     ConsumerOption.ACQUIRES), 0);
 
         final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
         EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries);
@@ -460,8 +462,8 @@
         ServerMessage messageC = createMessage(new Long(26));
 
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                      ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
 
         final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
         EntryListAddingAction postEnqueueAction = new EntryListAddingAction(queueEntries);
@@ -513,12 +515,12 @@
 
 
         QueueConsumer consumer1 = (QueueConsumer) _queue.addConsumer(target1, null, messageA.getClass(), "test",
-                                                                     EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                                    ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                                     EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                                ConsumerOption.SEES_REQUEUES), 0);
 
         QueueConsumer consumer2 = (QueueConsumer) _queue.addConsumer(target2, null, messageA.getClass(), "test",
-                                                                     EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                                    ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                                     EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                                ConsumerOption.SEES_REQUEUES), 0);
 
 
         final ArrayList<QueueEntry> queueEntries = new ArrayList<QueueEntry>();
@@ -555,8 +557,8 @@
         // Check adding an exclusive consumer adds it to the queue
 
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.EXCLUSIVE, ConsumerImpl.Option.ACQUIRES,
-                                                      ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.EXCLUSIVE, ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
 
         assertEquals("Queue does not have consumer", 1,
                      _queue.getConsumerCount());
@@ -585,8 +587,8 @@
         {
 
             _queue.addConsumer(subB, null, messageA.getClass(), "test",
-                               EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                          ConsumerImpl.Option.SEES_REQUEUES), 0);
+                               EnumSet.of(ConsumerOption.ACQUIRES,
+                                          ConsumerOption.SEES_REQUEUES), 0);
 
         }
         catch (MessageSource.ExistingExclusiveConsumer e)
@@ -599,14 +601,14 @@
         // existing consumer
         _consumer.close();
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, messageA.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                  ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                     ConsumerOption.SEES_REQUEUES), 0);
 
         try
         {
 
             _consumer = (QueueConsumer<?>) _queue.addConsumer(subB, null, messageA.getClass(), "test",
-                                                              EnumSet.of(ConsumerImpl.Option.EXCLUSIVE), 0);
+                                                              EnumSet.of(ConsumerOption.EXCLUSIVE), 0);
 
         }
         catch (MessageSource.ExistingConsumerPreventsExclusive e)
@@ -623,13 +625,13 @@
         ServerMessage message = createMessage(id);
 
         _consumer = (QueueConsumer<?>) _queue.addConsumer(_consumerTarget, null, message.getClass(), "test",
-                                                          EnumSet.of(ConsumerImpl.Option.ACQUIRES, ConsumerImpl.Option.SEES_REQUEUES),
+                                                          EnumSet.of(ConsumerOption.ACQUIRES, ConsumerOption.SEES_REQUEUES),
                                                           0);
 
-        _queue.enqueue(message, new Action<MessageInstance>()
+        _queue.enqueue(message, new Action<BaseMessageInstance>()
         {
             @Override
-            public void performAction(final MessageInstance object)
+            public void performAction(final BaseMessageInstance object)
             {
                 QueueEntryImpl entry = (QueueEntryImpl) object;
                 entry.setRedelivered();
@@ -1189,7 +1191,7 @@
         return message;
     }
 
-    private static class EntryListAddingAction implements Action<MessageInstance>
+    private static class EntryListAddingAction implements Action<BaseMessageInstance>
     {
         private final ArrayList<QueueEntry> _queueEntries;
 
@@ -1198,7 +1200,7 @@
             _queueEntries = queueEntries;
         }
 
-        public void performAction(MessageInstance entry)
+        public void performAction(BaseMessageInstance entry)
         {
             _queueEntries.add((QueueEntry) entry);
         }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/ConsumerListTest.java b/broker-core/src/test/java/org/apache/qpid/server/queue/ConsumerListTest.java
index 357c720..58993ec 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/ConsumerListTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/ConsumerListTest.java
@@ -21,13 +21,12 @@
 package org.apache.qpid.server.queue;
 
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.message.MessageInstance;
-import org.apache.qpid.test.utils.QpidTestCase;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.test.utils.QpidTestCase;
+
 public class ConsumerListTest extends QpidTestCase
 {
     private QueueConsumerList _subList;
@@ -147,7 +146,7 @@
      * Traverses the list nodes in a non-mutating fashion, returning the first node which matches the given
      * Consumer, or null if none is found.
      */
-    private ConsumerNode getNodeForConsumer(final QueueConsumerList list, final ConsumerImpl sub)
+    private ConsumerNode getNodeForConsumer(final QueueConsumerList list, final QueueConsumer sub)
     {
         ConsumerNode node = list.getHead();
         while (node != null && node.getConsumer() != sub)
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java b/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java
index 31534be..728a72a 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/MockMessageInstance.java
@@ -20,11 +20,12 @@
  */
 package org.apache.qpid.server.queue;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.filter.Filterable;
 import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
 import org.apache.qpid.server.store.TransactionLogResource;
@@ -49,7 +50,7 @@
     }
 
     @Override
-    public int routeToAlternate(final Action<? super MessageInstance> action,
+    public int routeToAlternate(final Action<? super BaseMessageInstance> action,
                                 final ServerTransaction txn)
     {
         return 0;
@@ -61,7 +62,7 @@
     }
 
     @Override
-    public ConsumerImpl getAcquiringConsumer()
+    public MessageInstanceConsumer getAcquiringConsumer()
     {
         return null;
     }
@@ -73,13 +74,13 @@
     }
 
     @Override
-    public boolean isAcquiredBy(final ConsumerImpl consumer)
+    public boolean isAcquiredBy(final MessageInstanceConsumer consumer)
     {
         return false;
     }
 
     @Override
-    public boolean removeAcquisitionFromConsumer(final ConsumerImpl consumer)
+    public boolean removeAcquisitionFromConsumer(final MessageInstanceConsumer consumer)
     {
         return false;
     }
@@ -95,13 +96,13 @@
     }
 
     @Override
-    public boolean acquire(final ConsumerImpl sub)
+    public boolean acquire(final MessageInstanceConsumer sub)
     {
         return false;
     }
 
     @Override
-    public boolean makeAcquisitionUnstealable(final ConsumerImpl consumer)
+    public boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer)
     {
         return false;
     }
@@ -117,7 +118,7 @@
         return false;
     }
 
-    public ConsumerImpl getDeliveredConsumer()
+    public MessageInstanceConsumer getDeliveredConsumer()
     {
         return null;
     }
@@ -147,7 +148,7 @@
     }
 
     @Override
-    public boolean isRejectedBy(final ConsumerImpl consumer)
+    public boolean isRejectedBy(final MessageInstanceConsumer consumer)
     {
         return false;
     }
@@ -158,7 +159,7 @@
     }
 
     @Override
-    public void release(final ConsumerImpl release)
+    public void release(final MessageInstanceConsumer release)
     {
     }
 
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java b/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java
index d9ec109..e307c5b 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/PriorityQueueTest.java
@@ -28,8 +28,8 @@
 
 import junit.framework.AssertionFailedError;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.ServerMessage;
 
@@ -63,7 +63,7 @@
         queue.enqueue(createMessage(9L, (byte) 0), null, null);
 
         // Register subscriber
-        queue.addConsumer(getConsumer(), null, null, "test", EnumSet.noneOf(ConsumerImpl.Option.class), 0);
+        queue.addConsumer(getConsumer(), null, null, "test", EnumSet.noneOf(ConsumerOption.class), 0);
         Thread.sleep(150);
 
         ArrayList<MessageInstance> msgs = getConsumer().getMessages();
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java b/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java
index 3e07bda..08f8dad 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/QueueEntryImplTestBase.java
@@ -145,7 +145,9 @@
         StealableConsumerAcquiredState
                 owningState = new StealableConsumerAcquiredState(consumer);
         when(consumer.getOwningState()).thenReturn(owningState);
-        when(consumer.getConsumerNumber()).thenReturn(_consumerId++);
+        final long consumerNum = _consumerId++;
+        when(consumer.getConsumerNumber()).thenReturn(consumerNum);
+        when(consumer.getIdentifier()).thenReturn(consumerNum);
         return consumer;
     }
 
@@ -298,7 +300,7 @@
 
         StandardQueueImpl queue = new StandardQueueImpl(queueAttributes, virtualHost);
         queue.open();
-        OrderedQueueEntryList queueEntryList = queue.getEntries();
+        OrderedBaseQueueEntryList queueEntryList = queue.getEntries();
 
         // create test entries
         for(int i = 0; i < numberOfEntries ; i++)
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java b/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java
index 7671218..691879d 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/SimpleQueueEntryImplTest.java
@@ -44,7 +44,7 @@
 public class SimpleQueueEntryImplTest extends QueueEntryImplTestBase
 {
 
-    private OrderedQueueEntryList queueEntryList;
+    private OrderedBaseQueueEntryList queueEntryList;
 
     @Override
     public void setUp() throws Exception
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java b/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java
index 2f4005c..44a65f1 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueEntryListTest.java
@@ -160,7 +160,7 @@
 
     public void testScavenge() throws Exception
     {
-        OrderedQueueEntryList sqel = new StandardQueueEntryList(mock(StandardQueueImpl.class));
+        OrderedBaseQueueEntryList sqel = new StandardQueueEntryList(mock(StandardQueueImpl.class));
         ConcurrentMap<Integer,QueueEntry> entriesMap = new ConcurrentHashMap<Integer,QueueEntry>();
 
 
@@ -265,7 +265,7 @@
     {
         final int numberOfEntries = 5;
         final OrderedQueueEntry[] entries = new OrderedQueueEntry[numberOfEntries];
-        final OrderedQueueEntryList queueEntryList = getTestList(true);
+        final OrderedBaseQueueEntryList queueEntryList = getTestList(true);
 
         // create test entries
         for(int i = 0; i < numberOfEntries; i++)
diff --git a/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java b/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java
index d386e49..aae05f4 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/queue/StandardQueueTest.java
@@ -29,10 +29,11 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.consumer.MockConsumer;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.LifetimePolicy;
 import org.apache.qpid.server.model.Queue;
@@ -57,8 +58,8 @@
         ServerMessage message = createMessage(25l);
         QueueConsumer consumer =
                 (QueueConsumer) getQueue().addConsumer(getConsumerTarget(), null, message.getClass(), "test",
-                                                       EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                                  ConsumerImpl.Option.SEES_REQUEUES), 0);
+                                                       EnumSet.of(ConsumerOption.ACQUIRES,
+                                                                  ConsumerOption.SEES_REQUEUES), 0);
 
         getQueue().enqueue(message, null, null);
         consumer.close();
@@ -83,8 +84,8 @@
                           null,
                           createMessage(-1l).getClass(),
                           "test",
-                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                     ConsumerImpl.Option.SEES_REQUEUES), 0);
+                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                     ConsumerOption.SEES_REQUEUES), 0);
         assertEquals("Unexpected active consumer count", 1, queue.getConsumerCountWithCredit());
 
         //verify adding an inactive consumer doesn't increase the count
@@ -96,8 +97,8 @@
                           null,
                           createMessage(-1l).getClass(),
                           "test",
-                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                     ConsumerImpl.Option.SEES_REQUEUES), 0);
+                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                     ConsumerOption.SEES_REQUEUES), 0);
         assertEquals("Unexpected active consumer count", 1, queue.getConsumerCountWithCredit());
 
         //verify behaviour in face of expected state changes:
@@ -151,8 +152,8 @@
                           null,
                           createMessage(-1l).getClass(),
                           "test",
-                          EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                     ConsumerImpl.Option.SEES_REQUEUES), 0);
+                          EnumSet.of(ConsumerOption.ACQUIRES,
+                                     ConsumerOption.SEES_REQUEUES), 0);
 
         // put test messages into a queue
         putGivenNumberOfMessages(queue, 4);
@@ -201,7 +202,7 @@
              * @param entry
              * @param batch
              */
-            public long send(final ConsumerImpl consumer, MessageInstance entry, boolean batch)
+            public long send(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
             {
                 long size = super.send(consumer, entry, batch);
                 latch.countDown();
@@ -214,8 +215,8 @@
                               null,
                               entries.get(0).getMessage().getClass(),
                               "test",
-                              EnumSet.of(ConsumerImpl.Option.ACQUIRES,
-                                         ConsumerImpl.Option.SEES_REQUEUES), 0);
+                              EnumSet.of(ConsumerOption.ACQUIRES,
+                                         ConsumerOption.SEES_REQUEUES), 0);
 
         // process queue
         testQueue.processQueue(new QueueRunner(testQueue, AccessController.getContext())
@@ -341,7 +342,7 @@
         }
 
         @Override
-        public boolean acquire(ConsumerImpl sub)
+        public boolean acquire(MessageInstanceConsumer sub)
         {
             if(_message.getMessageNumber() % 2 == 0)
             {
@@ -354,7 +355,7 @@
         }
 
         @Override
-        public boolean makeAcquisitionUnstealable(final ConsumerImpl consumer)
+        public boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer)
         {
             return true;
         }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/TrustStoreMessageSourceTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/TrustStoreMessageSourceTest.java
index 0f9569f..6cada6d 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/TrustStoreMessageSourceTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/TrustStoreMessageSourceTest.java
@@ -38,9 +38,10 @@
 import org.mockito.ArgumentCaptor;
 
 import org.apache.qpid.bytebuffer.QpidByteBuffer;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.State;
 import org.apache.qpid.server.model.TrustStore;
@@ -74,14 +75,14 @@
 
     public void testAddConsumer() throws Exception
     {
-        final EnumSet<ConsumerImpl.Option> options = EnumSet.noneOf(ConsumerImpl.Option.class);
+        final EnumSet<ConsumerOption> options = EnumSet.noneOf(ConsumerOption.class);
         final ConsumerTarget target = mock(ConsumerTarget.class);
         when(target.allocateCredit(any(ServerMessage.class))).thenReturn(true);
 
         _trustStoreMessageSource.addConsumer(target, null, ServerMessage.class, getTestName(), options, 0);
 
         ArgumentCaptor<MessageInstance> argumentCaptor = ArgumentCaptor.forClass(MessageInstance.class);
-        verify(target).send(any(ConsumerImpl.class), argumentCaptor.capture(), anyBoolean());
+        verify(target).send(any(MessageInstanceConsumer.class), argumentCaptor.capture(), anyBoolean());
         final ServerMessage message = argumentCaptor.getValue().getMessage();
         assertCertificates(getCertificatesFromMessage(message));
     }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecovererTest.java b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecovererTest.java
index f095f92..a948519 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecovererTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/AsynchronousMessageStoreRecovererTest.java
@@ -37,6 +37,7 @@
 import org.apache.qpid.server.store.MessageStore;
 import org.apache.qpid.server.store.TransactionLogResource;
 import org.apache.qpid.server.store.handler.MessageInstanceHandler;
+import org.apache.qpid.server.transfer.TransferQueue;
 import org.apache.qpid.server.util.ServerScopedRuntimeException;
 import org.apache.qpid.test.utils.QpidTestCase;
 
@@ -54,6 +55,9 @@
         _virtualHost = mock(VirtualHost.class);
         _store = mock(MessageStore.class);
         _storeReader = mock(MessageStore.MessageStoreReader.class);
+        TransferQueue tq = mock(TransferQueue.class);
+        when(tq.getName()).thenReturn("$transfer");
+        when(_virtualHost.getTransferQueue()).thenReturn(tq);
 
         when(_virtualHost.getEventLogger()).thenReturn(new EventLogger());
         when(_virtualHost.getMessageStore()).thenReturn(_store);
diff --git a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecovererTest.java b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecovererTest.java
index 55fde08..d5821c1 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecovererTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/SynchronousMessageStoreRecovererTest.java
@@ -32,15 +32,14 @@
 
 import java.util.UUID;
 
-import org.apache.qpid.server.model.Queue;
-import org.apache.qpid.server.model.VirtualHost;
-import org.apache.qpid.test.utils.QpidTestCase;
 import org.mockito.ArgumentMatcher;
 
 import org.apache.qpid.server.logging.EventLogger;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.EnqueueableMessage;
-import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.queue.QueueEntry;
 import org.apache.qpid.server.store.MessageDurability;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
@@ -55,9 +54,11 @@
 import org.apache.qpid.server.store.handler.DistributedTransactionHandler;
 import org.apache.qpid.server.store.handler.MessageHandler;
 import org.apache.qpid.server.store.handler.MessageInstanceHandler;
+import org.apache.qpid.server.transfer.TransferQueue;
 import org.apache.qpid.server.txn.DtxBranch;
 import org.apache.qpid.server.txn.DtxRegistry;
 import org.apache.qpid.server.util.Action;
+import org.apache.qpid.test.utils.QpidTestCase;
 import org.apache.qpid.transport.Xid;
 
 public class SynchronousMessageStoreRecovererTest extends QpidTestCase
@@ -70,7 +71,11 @@
         super.setUp();
 
         _virtualHost = mock(VirtualHost.class);
+        TransferQueue tq = mock(TransferQueue.class);
+        UUID tqId = UUID.randomUUID();
+        when(tq.getId()).thenReturn(tqId);
         when(_virtualHost.getEventLogger()).thenReturn(new EventLogger());
+        when(_virtualHost.getTransferQueue()).thenReturn(tq);
 
     }
 
@@ -294,7 +299,7 @@
         branch.commit();
 
         ServerMessage<?> message = storedMessage.getMetaData().getType().createMessage(storedMessage);
-        verify(queue, times(1)).enqueue(eq(message), (Action<? super MessageInstance>)isNull(), any(MessageEnqueueRecord.class));
+        verify(queue, times(1)).enqueue(eq(message), (Action<? super BaseMessageInstance>)isNull(), any(MessageEnqueueRecord.class));
         verify(transaction).commitTran();
     }
 
diff --git a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNodeTest.java b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNodeTest.java
index dd2dd47..11e73e5 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNodeTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/virtualhost/VirtualHostPropertiesNodeTest.java
@@ -26,9 +26,10 @@
 
 import java.util.EnumSet;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.VirtualHost;
 import org.apache.qpid.server.store.MessageStore;
@@ -52,11 +53,11 @@
 
     public void testAddConsumer() throws Exception
     {
-        final EnumSet<ConsumerImpl.Option> options = EnumSet.noneOf(ConsumerImpl.Option.class);
+        final EnumSet<ConsumerOption> options = EnumSet.noneOf(ConsumerOption.class);
         final ConsumerTarget target = mock(ConsumerTarget.class);
         when(target.allocateCredit(any(ServerMessage.class))).thenReturn(true);
 
         _virtualHostPropertiesNode.addConsumer(target, null, ServerMessage.class, getTestName(), options, 0);
-        verify(target).send(any(ConsumerImpl.class), any(MessageInstance.class), anyBoolean());
+        verify(target).send(any(MessageInstanceConsumer.class), any(MessageInstance.class), anyBoolean());
     }
 }
diff --git a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java
index cfb6770..b93be3d 100644
--- a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java
+++ b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ConsumerTarget_0_10.java
@@ -31,13 +31,14 @@
 
 import org.apache.qpid.bytebuffer.QpidByteBuffer;
 import org.apache.qpid.server.consumer.AbstractConsumerTarget;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.flow.FlowCreditManager;
 import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.messages.ChannelMessages;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageInstance.ConsumerAcquiredState;
 import org.apache.qpid.server.message.MessageInstance.EntryState;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.Queue;
@@ -148,7 +149,6 @@
         // TODO check for Session suspension
     }
 
-    @Override
     protected void doCloseInternal()
     {
         _creditManager.removeListener(this);
@@ -213,7 +213,7 @@
 
     private final AddMessageDispositionListenerAction _postIdSettingAction;
 
-    public void doSend(final ConsumerImpl consumer, final MessageInstance entry, boolean batch)
+    public void doSend(final MessageInstanceConsumer consumer, final MessageInstance entry, boolean batch)
     {
         ServerMessage serverMsg = entry.getMessage();
 
@@ -435,7 +435,7 @@
                            });
    }
 
-    void reject(final ConsumerImpl consumer, final MessageInstance entry)
+    void reject(final MessageInstanceConsumer consumer, final MessageInstance entry)
     {
         entry.setRedelivered();
         if (entry.makeAcquisitionUnstealable(consumer))
@@ -444,7 +444,7 @@
         }
     }
 
-    void release(final ConsumerImpl consumer,
+    void release(final MessageInstanceConsumer consumer,
                  final MessageInstance entry,
                  final boolean setRedelivered)
     {
@@ -468,17 +468,17 @@
         }
     }
 
-    protected void sendToDLQOrDiscard(final ConsumerImpl consumer, MessageInstance entry)
+    protected void sendToDLQOrDiscard(final MessageInstanceConsumer consumer, MessageInstance entry)
     {
         final ServerMessage msg = entry.getMessage();
 
         int requeues = 0;
         if (entry.makeAcquisitionUnstealable(consumer))
         {
-            requeues = entry.routeToAlternate(new Action<MessageInstance>()
+            requeues = entry.routeToAlternate(new Action<BaseMessageInstance>()
             {
                 @Override
-                public void performAction(final MessageInstance requeueEntry)
+                public void performAction(final BaseMessageInstance requeueEntry)
                 {
                     getEventLogger().message(ChannelMessages.DEADLETTERMSG(msg.getMessageNumber(),
                                                                            requeueEntry.getOwningResource()
@@ -614,7 +614,7 @@
     public void flush()
     {
         flushCreditState(true);
-        for(ConsumerImpl consumer : getConsumers())
+        for(MessageInstanceConsumer consumer : getConsumers())
         {
             consumer.flush();
         }
diff --git a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ExplicitAcceptDispositionChangeListener.java b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ExplicitAcceptDispositionChangeListener.java
index 0a12dfd..283315d 100755
--- a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ExplicitAcceptDispositionChangeListener.java
+++ b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ExplicitAcceptDispositionChangeListener.java
@@ -23,8 +23,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 
 
 class ExplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener
@@ -34,11 +34,11 @@
 
     private final MessageInstance _entry;
     private final ConsumerTarget_0_10 _target;
-    private final ConsumerImpl _consumer;
+    private final MessageInstanceConsumer _consumer;
 
     public ExplicitAcceptDispositionChangeListener(MessageInstance entry,
                                                    ConsumerTarget_0_10 target,
-                                                   final ConsumerImpl consumer)
+                                                   final MessageInstanceConsumer consumer)
     {
         _entry = entry;
         _target = target;
diff --git a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ImplicitAcceptDispositionChangeListener.java b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ImplicitAcceptDispositionChangeListener.java
index 10bc474..8adf027 100755
--- a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ImplicitAcceptDispositionChangeListener.java
+++ b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ImplicitAcceptDispositionChangeListener.java
@@ -23,8 +23,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 
 class ImplicitAcceptDispositionChangeListener implements ServerSession.MessageDispositionChangeListener
 {
@@ -33,11 +33,11 @@
 
     private final MessageInstance _entry;
     private final ConsumerTarget_0_10 _target;
-    private final ConsumerImpl _consumer;
+    private final MessageInstanceConsumer _consumer;
 
     public ImplicitAcceptDispositionChangeListener(MessageInstance entry,
                                                    ConsumerTarget_0_10 target,
-                                                   final ConsumerImpl consumer)
+                                                   final MessageInstanceConsumer consumer)
     {
         _entry = entry;
         _target = target;
diff --git a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageAcceptCompletionListener.java b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageAcceptCompletionListener.java
index d1a4d27..3641415 100755
--- a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageAcceptCompletionListener.java
+++ b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/MessageAcceptCompletionListener.java
@@ -21,8 +21,8 @@
 
 package org.apache.qpid.server.protocol.v0_10;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.transport.Method;
 
 public class MessageAcceptCompletionListener implements Method.CompletionListener
@@ -30,12 +30,12 @@
     private final ConsumerTarget_0_10 _sub;
     private final MessageInstance _entry;
     private final ServerSession _session;
-    private final ConsumerImpl _consumer;
+    private final MessageInstanceConsumer _consumer;
     private long _messageSize;
     private boolean _restoreCredit;
 
     public MessageAcceptCompletionListener(ConsumerTarget_0_10 sub,
-                                           final ConsumerImpl consumer,
+                                           final MessageInstanceConsumer consumer,
                                            ServerSession session,
                                            MessageInstance entry,
                                            boolean restoreCredit)
diff --git a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java
index 8afa6aa..cb1fb9b 100644
--- a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java
+++ b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSession.java
@@ -56,15 +56,17 @@
 
 import org.apache.qpid.protocol.AMQConstant;
 import org.apache.qpid.server.connection.SessionPrincipal;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.logging.LogMessage;
 import org.apache.qpid.server.logging.LogSubject;
 import org.apache.qpid.server.logging.messages.ChannelMessages;
 import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
@@ -536,7 +538,7 @@
         // Broker shouldn't block awaiting close - thus do override this method to do nothing
     }
 
-    public void acknowledge(final ConsumerImpl consumer,
+    public void acknowledge(final MessageInstanceConsumer consumer,
                             final ConsumerTarget_0_10 target,
                             final MessageInstance entry)
     {
@@ -573,14 +575,14 @@
     }
 
 
-    public void register(final ConsumerImpl consumerImpl)
+    public void register(final MessageInstanceConsumer consumer)
     {
-        if(consumerImpl instanceof Consumer<?>)
+        if(consumer instanceof Consumer<?>)
         {
-            final Consumer<?> consumer = (Consumer<?>) consumerImpl;
-            _consumers.add(consumer);
-            consumer.addChangeListener(_consumerClosedListener);
-            consumerAdded(consumer);
+            final Consumer<?> modelConsumer = (Consumer<?>) consumer;
+            _consumers.add(modelConsumer);
+            modelConsumer.addChangeListener(_consumerClosedListener);
+            consumerAdded(modelConsumer);
         }
     }
 
@@ -1296,10 +1298,10 @@
         return getId().compareTo(o.getId());
     }
 
-    private class CheckCapacityAction implements Action<MessageInstance>
+    private class CheckCapacityAction implements Action<BaseMessageInstance>
     {
         @Override
-        public void performAction(final MessageInstance entry)
+        public void performAction(final BaseMessageInstance entry)
         {
             TransactionLogResource queue = entry.getOwningResource();
             if(queue instanceof CapacityChecker)
@@ -1309,7 +1311,7 @@
         }
     }
 
-    private class ConsumerClosedListener implements ConfigurationChangeListener
+    private class ConsumerClosedListener extends AbstractConfigurationChangeListener
     {
         @Override
         public void stateChanged(final ConfiguredObject object, final org.apache.qpid.server.model.State oldState, final org.apache.qpid.server.model.State newState)
@@ -1320,37 +1322,5 @@
             }
         }
 
-        @Override
-        public void childAdded(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void childRemoved(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void attributeSet(final ConfiguredObject object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-
-        }
     }
 }
diff --git a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java
index 898edd6..a999d4e 100644
--- a/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java
+++ b/broker-plugins/amqp-0-10-protocol/src/main/java/org/apache/qpid/server/protocol/v0_10/ServerSessionDelegate.java
@@ -39,7 +39,6 @@
 import org.apache.qpid.common.AMQPFilterTypes;
 import org.apache.qpid.exchange.ExchangeDefaults;
 import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.filter.AMQInvalidArgumentException;
 import org.apache.qpid.server.filter.ArrivalTimeFilter;
 import org.apache.qpid.server.filter.FilterManager;
@@ -48,6 +47,7 @@
 import org.apache.qpid.server.logging.EventLogger;
 import org.apache.qpid.server.logging.messages.ChannelMessages;
 import org.apache.qpid.server.logging.messages.ExchangeMessages;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
 import org.apache.qpid.server.message.MessageReference;
@@ -338,18 +338,18 @@
                     ((ServerSession)session).register(destination, target);
                     try
                     {
-                        EnumSet<ConsumerImpl.Option> options = EnumSet.noneOf(ConsumerImpl.Option.class);
+                        EnumSet<ConsumerOption> options = EnumSet.noneOf(ConsumerOption.class);
                         if(method.getAcquireMode() == MessageAcquireMode.PRE_ACQUIRED)
                         {
-                            options.add(ConsumerImpl.Option.ACQUIRES);
+                            options.add(ConsumerOption.ACQUIRES);
                         }
                         if(method.getAcquireMode() != MessageAcquireMode.NOT_ACQUIRED || method.getAcceptMode() == MessageAcceptMode.EXPLICIT)
                         {
-                            options.add(ConsumerImpl.Option.SEES_REQUEUES);
+                            options.add(ConsumerOption.SEES_REQUEUES);
                         }
                         if(method.getExclusive())
                         {
-                            options.add(ConsumerImpl.Option.EXCLUSIVE);
+                            options.add(ConsumerOption.EXCLUSIVE);
                         }
                         for(MessageSource source : sources)
                         {
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java
index ccfb99e..46d5939 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQChannel.java
@@ -57,7 +57,6 @@
 import org.apache.qpid.framing.*;
 import org.apache.qpid.protocol.AMQConstant;
 import org.apache.qpid.server.connection.SessionPrincipal;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.AMQInvalidArgumentException;
 import org.apache.qpid.server.filter.ArrivalTimeFilter;
@@ -73,12 +72,16 @@
 import org.apache.qpid.server.logging.messages.ChannelMessages;
 import org.apache.qpid.server.logging.messages.ExchangeMessages;
 import org.apache.qpid.server.logging.subjects.ChannelLogSubject;
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
@@ -307,7 +310,7 @@
         final RecordDeliveryMethod getRecordMethod = new RecordDeliveryMethod()
         {
 
-            public void recordMessageDelivery(final ConsumerImpl sub,
+            public void recordMessageDelivery(final MessageInstanceConsumer sub,
                                               final MessageInstance entry,
                                               final long deliveryTag)
             {
@@ -316,8 +319,8 @@
         };
 
         ConsumerTarget_0_8 target;
-        EnumSet<ConsumerImpl.Option> options = EnumSet.of(ConsumerImpl.Option.TRANSIENT, ConsumerImpl.Option.ACQUIRES,
-                                                          ConsumerImpl.Option.SEES_REQUEUES);
+        EnumSet<ConsumerOption> options = EnumSet.of(ConsumerOption.TRANSIENT, ConsumerOption.ACQUIRES,
+                                                     ConsumerOption.SEES_REQUEUES);
         if (acks)
         {
 
@@ -332,7 +335,7 @@
                                                              singleMessageCredit, getDeliveryMethod, getRecordMethod);
         }
 
-        ConsumerImpl sub = queue.addConsumer(target, null, AMQMessage.class, "", options, null);
+        MessageInstanceConsumer sub = queue.addConsumer(target, null, AMQMessage.class, "", options, null);
         sub.flush();
         sub.close();
         return getDeliveryMethod.hasDeliveredMessage();
@@ -629,12 +632,13 @@
         }
         else
         {
+            if(_confirmOnPublish)
+            {
+                _connection.writeFrame(new AMQFrame(_channelId, new BasicNackBody(_confirmedMessageCounter, false, false)));
+            }
+
             if (mandatory || message.isImmediate())
             {
-                if(_confirmOnPublish)
-                {
-                    _connection.writeFrame(new AMQFrame(_channelId, new BasicNackBody(_confirmedMessageCounter, false, false)));
-                }
                 _transaction.addPostTransactionAction(new WriteReturnAction(AMQConstant.NO_ROUTE,
                                                                             "No Route for message "
                                                                             + description,
@@ -726,7 +730,7 @@
         }
 
         ConsumerTarget_0_8 target;
-        EnumSet<ConsumerImpl.Option> options = EnumSet.noneOf(ConsumerImpl.Option.class);
+        EnumSet<ConsumerOption> options = EnumSet.noneOf(ConsumerOption.class);
         final boolean multiQueue = sources.size()>1;
         if(arguments != null && Boolean.TRUE.equals(arguments.get(AMQPFilterTypes.NO_CONSUME.getValue())))
         {
@@ -735,19 +739,19 @@
         else if(acks)
         {
             target = ConsumerTarget_0_8.createAckTarget(this, tag, arguments, _creditManager, multiQueue);
-            options.add(ConsumerImpl.Option.ACQUIRES);
-            options.add(ConsumerImpl.Option.SEES_REQUEUES);
+            options.add(ConsumerOption.ACQUIRES);
+            options.add(ConsumerOption.SEES_REQUEUES);
         }
         else
         {
             target = ConsumerTarget_0_8.createNoAckTarget(this, tag, arguments, _noAckCreditManager, multiQueue);
-            options.add(ConsumerImpl.Option.ACQUIRES);
-            options.add(ConsumerImpl.Option.SEES_REQUEUES);
+            options.add(ConsumerOption.ACQUIRES);
+            options.add(ConsumerOption.SEES_REQUEUES);
         }
 
         if(exclusive)
         {
-            options.add(ConsumerImpl.Option.EXCLUSIVE);
+            options.add(ConsumerOption.EXCLUSIVE);
         }
 
 
@@ -831,7 +835,7 @@
 
             for(MessageSource source : sources)
             {
-                ConsumerImpl sub =
+                MessageInstanceConsumer sub =
                         source.addConsumer(target,
                                            filterManager,
                                            AMQMessage.class,
@@ -871,15 +875,15 @@
         }
 
         ConsumerTarget_0_8 target = _tag2SubscriptionTargetMap.remove(consumerTag);
-        Collection<ConsumerImpl> subs = target == null ? null : target.getConsumers();
-        if (subs != null)
+        Collection<MessageInstanceConsumer> consumers = target == null ? null : target.getConsumers();
+        if (consumers != null)
         {
-            for(ConsumerImpl sub : subs)
+            for(MessageInstanceConsumer consumer : consumers)
             {
-                sub.close();
-                if (sub instanceof Consumer<?>)
+                consumer.close();
+                if (consumer instanceof Consumer<?>)
                 {
-                    _consumers.remove(sub);
+                    _consumers.remove(consumer);
                 }
             }
             return true;
@@ -959,13 +963,12 @@
 
     /**
      * Add a message to the channel-based list of unacknowledged messages
-     *
-     * @param entry       the record of the message on the queue that was delivered
+     *  @param entry       the record of the message on the queue that was delivered
      * @param deliveryTag the delivery tag used when delivering the message (see protocol spec for description of the
      *                    delivery tag)
      * @param consumer The consumer that is to acknowledge this message.
      */
-    public void addUnacknowledgedMessage(MessageInstance entry, long deliveryTag, ConsumerImpl consumer)
+    public void addUnacknowledgedMessage(MessageInstance entry, long deliveryTag, MessageInstanceConsumer consumer)
     {
         if (_logger.isDebugEnabled())
         {
@@ -1211,9 +1214,9 @@
                 // may need to deliver queued messages
                 for (ConsumerTarget_0_8 s : getConsumerTargets())
                 {
-                    for(ConsumerImpl sub : s.getConsumers())
+                    for(MessageInstanceConsumer consumer : s.getConsumers())
                     {
-                        sub.externalStateChange();
+                        consumer.externalStateChange();
                     }
                 }
             }
@@ -1319,7 +1322,7 @@
 
         for(MessageInstance entry : _resendList)
         {
-            ConsumerImpl sub = entry.getAcquiringConsumer();
+            MessageInstanceConsumer sub = entry.getAcquiringConsumer();
             if (sub == null || sub.isClosed())
             {
                 entry.release(sub);
@@ -1336,9 +1339,9 @@
             _suspended.set(false);
             for(ConsumerTarget_0_8 target : getConsumerTargets())
             {
-                for(ConsumerImpl sub : target.getConsumers())
+                for(MessageInstanceConsumer consumer : target.getConsumers())
                 {
-                    sub.externalStateChange();
+                    consumer.externalStateChange();
                 }
             }
 
@@ -1388,7 +1391,7 @@
     private final RecordDeliveryMethod _recordDeliveryMethod = new RecordDeliveryMethod()
         {
 
-            public void recordMessageDelivery(final ConsumerImpl sub, final MessageInstance entry, final long deliveryTag)
+            public void recordMessageDelivery(final MessageInstanceConsumer sub, final MessageInstance entry, final long deliveryTag)
             {
                 addUnacknowledgedMessage(entry, deliveryTag, sub);
             }
@@ -1508,7 +1511,7 @@
         }
 
         @Override
-        public long deliverToClient(final ConsumerImpl sub, final ServerMessage message,
+        public long deliverToClient(final MessageInstanceConsumer consumer, final ServerMessage message,
                                     final InstanceProperties props, final long deliveryTag)
         {
             _singleMessageCredit.useCreditForMessage(message.getSize());
@@ -1530,14 +1533,14 @@
     }
 
 
-    private class ImmediateAction implements Action<MessageInstance>
+    private class ImmediateAction implements Action<BaseMessageInstance>
     {
 
         public ImmediateAction()
         {
         }
 
-        public void performAction(MessageInstance entry)
+        public void performAction(BaseMessageInstance entry)
         {
             TransactionLogResource queue = entry.getOwningResource();
 
@@ -1595,10 +1598,10 @@
         }
     }
 
-    private final class CapacityCheckAction implements Action<MessageInstance>
+    private final class CapacityCheckAction implements Action<BaseMessageInstance>
     {
         @Override
-        public void performAction(final MessageInstance entry)
+        public void performAction(final BaseMessageInstance entry)
         {
             TransactionLogResource queue = entry.getOwningResource();
             if(queue instanceof CapacityChecker)
@@ -1800,10 +1803,10 @@
             int requeues = 0;
             if (rejectedQueueEntry.makeAcquisitionUnstealable(rejectedQueueEntry.getAcquiringConsumer()))
             {
-                requeues = rejectedQueueEntry.routeToAlternate(new Action<MessageInstance>()
+                requeues = rejectedQueueEntry.routeToAlternate(new Action<BaseMessageInstance>()
                 {
                     @Override
-                    public void performAction(final MessageInstance requeueEntry)
+                    public void performAction(final BaseMessageInstance requeueEntry)
                     {
                         messageWithSubject(ChannelMessages.DEADLETTERMSG(msg.getMessageNumber(),
                                                                          requeueEntry.getOwningResource()
@@ -1941,7 +1944,7 @@
         return Collections.unmodifiableCollection(_consumers);
     }
 
-    private class ConsumerClosedListener implements ConfigurationChangeListener
+    private class ConsumerClosedListener extends AbstractConfigurationChangeListener
     {
         @Override
         public void stateChanged(final ConfiguredObject object, final State oldState, final State newState)
@@ -1952,38 +1955,6 @@
             }
         }
 
-        @Override
-        public void childAdded(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void childRemoved(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void attributeSet(final ConfiguredObject object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-
-        }
     }
 
     private void consumerAdded(final Consumer<?> consumer)
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java
index 3a51f36..68aaaea 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/AMQPConnection_0_8Impl.java
@@ -61,9 +61,9 @@
 import org.apache.qpid.properties.ConnectionStartProperties;
 import org.apache.qpid.protocol.AMQConstant;
 import org.apache.qpid.server.configuration.BrokerProperties;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.logging.messages.ConnectionMessages;
 import org.apache.qpid.server.message.InstanceProperties;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.Broker;
 import org.apache.qpid.server.model.NamedAddressSpace;
@@ -757,7 +757,7 @@
         }, getAccessControllerContext());
     }
 
-    public synchronized void writerIdle()
+    public void writerIdle()
     {
         writeFrame(HeartbeatBody.FRAME);
     }
@@ -1269,14 +1269,14 @@
         }
 
         @Override
-        public long deliverToClient(final ConsumerImpl sub, final ServerMessage message,
+        public long deliverToClient(final MessageInstanceConsumer consumer, final ServerMessage message,
                                     final InstanceProperties props, final long deliveryTag)
         {
             long size = _protocolOutputConverter.writeDeliver(message,
                                                   props,
                                                   _channelId,
                                                   deliveryTag,
-                                                  new AMQShortString(sub.getName()));
+                                                  new AMQShortString(consumer.getName()));
             registerMessageDelivered(size);
             return size;
         }
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java
index c7871e8..3703b02 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ClientDeliveryMethod.java
@@ -20,12 +20,12 @@
 */
 package org.apache.qpid.server.protocol.v0_8;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.InstanceProperties;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 
 public interface ClientDeliveryMethod
 {
-    long deliverToClient(final ConsumerImpl sub, final ServerMessage message, final InstanceProperties props,
+    long deliverToClient(final MessageInstanceConsumer consumer, final ServerMessage message, final InstanceProperties props,
                          final long deliveryTag);
 }
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java
index 8736eca..c549fe1 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ConsumerTarget_0_8.java
@@ -28,11 +28,11 @@
 import org.apache.qpid.framing.AMQShortString;
 import org.apache.qpid.framing.FieldTable;
 import org.apache.qpid.server.consumer.AbstractConsumerTarget;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.flow.FlowCreditManager;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageInstance.EntryState;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageReference;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.protocol.AMQSessionModel;
@@ -102,7 +102,7 @@
          * @throws QpidException
          */
         @Override
-        public void doSend(final ConsumerImpl consumer, MessageInstance entry, boolean batch)
+        public void doSend(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
         {
             // We don't decrement the reference here as we don't want to consume the message
             // but we do want to send it to the client.
@@ -146,13 +146,12 @@
         /**
          * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
          * thread safe.
-         *
-         * @param consumer
+         *  @param consumer
          * @param entry   The message to send
          * @param batch
          */
         @Override
-        public void doSend(final ConsumerImpl consumer, MessageInstance entry, boolean batch)
+        public void doSend(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
         {
             // if we do not need to wait for client acknowledgements
             // we can decrement the reference count immediately.
@@ -253,13 +252,12 @@
         /**
          * This method can be called by each of the publisher threads. As a result all changes to the channel object must be
          * thread safe.
-         *
-         * @param consumer
+         *  @param consumer
          * @param entry   The message to send
          * @param batch
          */
         @Override
-        public void doSend(final ConsumerImpl consumer, MessageInstance entry, boolean batch)
+        public void doSend(final MessageInstanceConsumer consumer, MessageInstance entry, boolean batch)
         {
 
             // put queue entry on a list and then notify the connection to read list.
@@ -350,8 +348,6 @@
                && Boolean.valueOf(String.valueOf(arguments.get(PULL_ONLY_CONSUMER)));
     }
 
-
-
     @Override
     public String getTargetAddress()
     {
@@ -444,7 +440,7 @@
         }
     }
 
-    protected long sendToClient(final ConsumerImpl consumer, final ServerMessage message,
+    protected long sendToClient(final MessageInstanceConsumer consumer, final ServerMessage message,
                                 final InstanceProperties props,
                                 final long deliveryTag)
     {
@@ -453,7 +449,7 @@
     }
 
 
-    protected void recordMessageDelivery(final ConsumerImpl consumer,
+    protected void recordMessageDelivery(final MessageInstanceConsumer consumer,
                                          final MessageInstance entry,
                                          final long deliveryTag)
     {
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeue.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeue.java
index 98fd6b6..634cecf 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeue.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeue.java
@@ -25,8 +25,8 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 
 public class ExtractResendAndRequeue implements UnacknowledgedMessageMap.Visitor
 {
@@ -49,7 +49,7 @@
     {
 
         message.setRedelivered();
-        final ConsumerImpl consumer = message.getDeliveredConsumer();
+        final MessageInstanceConsumer consumer = message.getDeliveredConsumer();
         if (consumer != null)
         {
             // Consumer exists
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageContentSourceBody.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageContentSourceBody.java
new file mode 100644
index 0000000..50f17e6
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/MessageContentSourceBody.java
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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.protocol.v0_8;
+
+import org.apache.qpid.QpidException;
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.server.message.MessageContentSource;
+import org.apache.qpid.transport.ByteBufferSender;
+
+public class MessageContentSourceBody implements AMQBody
+{
+    public static final byte TYPE = 3;
+    private final int _length;
+    private final MessageContentSource _content;
+    private final int _offset;
+
+    public MessageContentSourceBody(MessageContentSource content, int offset, int length)
+    {
+        _content = content;
+        _offset = offset;
+        _length = length;
+    }
+
+    public byte getFrameType()
+    {
+        return TYPE;
+    }
+
+    public int getSize()
+    {
+        return _length;
+    }
+
+    @Override
+    public long writePayload(final ByteBufferSender sender)
+    {
+        long size = 0L;
+        for(QpidByteBuffer buf : _content.getContent(_offset, _length))
+        {
+            size += buf.remaining();
+
+            sender.send(buf);
+            buf.dispose();
+        }
+        return size;
+    }
+
+    public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws QpidException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "[" + getClass().getSimpleName() + " offset: " + _offset + ", length: " + _length + "]";
+    }
+
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ProtocolOutputConverterImpl.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ProtocolOutputConverterImpl.java
index a66318a..6bab565 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ProtocolOutputConverterImpl.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/ProtocolOutputConverterImpl.java
@@ -246,57 +246,6 @@
         return GZIP_ENCODING.equals(contentHeaderBody.getProperties().getEncoding());
     }
 
-    private class MessageContentSourceBody implements AMQBody
-    {
-        public static final byte TYPE = 3;
-        private final int _length;
-        private final MessageContentSource _content;
-        private final int _offset;
-
-        public MessageContentSourceBody(MessageContentSource content, int offset, int length)
-        {
-            _content = content;
-            _offset = offset;
-            _length = length;
-        }
-
-        public byte getFrameType()
-        {
-            return TYPE;
-        }
-
-        public int getSize()
-        {
-            return _length;
-        }
-
-        @Override
-        public long writePayload(final ByteBufferSender sender)
-        {
-            long size = 0L;
-            for(QpidByteBuffer buf : _content.getContent(_offset, _length))
-            {
-                size += buf.remaining();
-
-                sender.send(buf);
-                buf.dispose();
-            }
-            return size;
-        }
-
-        public void handle(int channelId, AMQVersionAwareProtocolSession amqProtocolSession) throws QpidException
-        {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public String toString()
-        {
-            return "[" + getClass().getSimpleName() + " offset: " + _offset + ", length: " + _length + "]";
-        }
-
-    }
-
     public long writeGetOk(final ServerMessage msg,
                            final InstanceProperties props,
                            int channelId,
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/RecordDeliveryMethod.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/RecordDeliveryMethod.java
index c13ff17..34a17a4 100644
--- a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/RecordDeliveryMethod.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/RecordDeliveryMethod.java
@@ -20,10 +20,10 @@
 */
 package org.apache.qpid.server.protocol.v0_8;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 
 public interface RecordDeliveryMethod
 {
-    void recordMessageDelivery(final ConsumerImpl sub, final MessageInstance entry, final long deliveryTag);
+    void recordMessageDelivery(final MessageInstanceConsumer sub, final MessageInstance entry, final long deliveryTag);
 }
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/FederationDecoder.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/FederationDecoder.java
new file mode 100644
index 0000000..01eb3bb
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/FederationDecoder.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.codec.ClientDecoder;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQProtocolVersionException;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+class FederationDecoder extends ClientDecoder
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(FederationDecoder.class);
+
+
+    private final OutboundConnection_0_8 _connection;
+
+    FederationDecoder(final OutboundConnection_0_8 connection)
+    {
+        super(connection);
+        _connection = connection;
+    }
+
+    public void decodeBuffer(QpidByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
+    {
+        decode(buf);
+    }
+
+    @Override
+    protected void processFrame(final int channelId, final byte type, final long bodySize, final QpidByteBuffer in)
+            throws AMQFrameDecodingException
+    {
+        long startTime = 0;
+        try
+        {
+            if (LOGGER.isDebugEnabled())
+            {
+                startTime = System.currentTimeMillis();
+            }
+            OutboundChannel channel = _connection.getChannel(channelId);
+            if(channel == null)
+            {
+                doProcessFrame(channelId, type, bodySize, in);
+            }
+            else
+            {
+
+                try
+                {
+                    AccessController.doPrivileged(new PrivilegedExceptionAction<Object>()
+                    {
+                        @Override
+                        public Void run() throws IOException, AMQFrameDecodingException
+                        {
+                            doProcessFrame(channelId, type, bodySize, in);
+                            return null;
+                        }
+                    }, channel.getAccessControllerContext());
+                }
+                catch (PrivilegedActionException e)
+                {
+                    Throwable cause = e.getCause();
+                    if(cause instanceof AMQFrameDecodingException)
+                    {
+                        throw (AMQFrameDecodingException) cause;
+                    }
+                    else if(cause instanceof RuntimeException)
+                    {
+                        throw (RuntimeException) cause;
+                    }
+                    else
+                    {
+                        throw new ServerScopedRuntimeException(cause);
+                    }
+                }
+            }
+        }
+        finally
+        {
+            if(LOGGER.isDebugEnabled())
+            {
+                LOGGER.debug("Frame handled in {} ms.", (System.currentTimeMillis() - startTime));
+            }
+        }
+    }
+
+
+    private void doProcessFrame(final int channelId, final byte type, final long bodySize, final QpidByteBuffer in)
+            throws AMQFrameDecodingException
+    {
+        super.processFrame(channelId, type, bodySize, in);
+
+    }
+
+
+}
diff --git a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundChannel.java
similarity index 70%
copy from broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
copy to broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundChannel.java
index 7ca5c6d..4769f2f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/message/MessageSourceConsumer.java
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundChannel.java
@@ -18,11 +18,17 @@
  * under the License.
  *
  */
-package org.apache.qpid.server.message;
+package org.apache.qpid.server.protocol.v0_8.federation;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.model.Consumer;
+import java.security.AccessControlContext;
 
-public interface MessageSourceConsumer<X extends MessageSourceConsumer<X>> extends ConsumerImpl, Consumer<MessageSourceConsumer<X>>
+import org.apache.qpid.framing.ClientChannelMethodProcessor;
+
+interface OutboundChannel extends ClientChannelMethodProcessor
 {
+    AccessControlContext getAccessControllerContext();
+
+    boolean processPending();
+
+    void receivedComplete();
 }
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundConnection_0_8.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundConnection_0_8.java
new file mode 100644
index 0000000..9ddb011
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundConnection_0_8.java
@@ -0,0 +1,772 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.security.auth.Subject;
+import javax.security.auth.SubjectDomainCombiner;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.common.ServerPropertyNames;
+import org.apache.qpid.configuration.CommonProperties;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.ClientChannelMethodProcessor;
+import org.apache.qpid.framing.ClientMethodProcessor;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.FieldTableFactory;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.server.configuration.BrokerProperties;
+import org.apache.qpid.server.federation.OutboundProtocolEngine;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.Credential;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.RemoteHost;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.store.StoreException;
+import org.apache.qpid.server.transport.AggregateTicker;
+import org.apache.qpid.server.transport.ProtocolEngine;
+import org.apache.qpid.server.transport.SchedulableConnection;
+import org.apache.qpid.server.transport.ServerIdleReadTimeoutTicker;
+import org.apache.qpid.server.transport.ServerIdleWriteTimeoutTicker;
+import org.apache.qpid.server.util.Action;
+import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+
+class OutboundConnection_0_8 implements OutboundProtocolEngine, ClientMethodProcessor<ClientChannelMethodProcessor>
+{
+
+    private static final Map<Protocol, ProtocolVersion> PROTOCOL_VERSION_MAP;
+
+    static
+    {
+        Map<Protocol, ProtocolVersion> protocolVersionMap = new HashMap<>();
+        protocolVersionMap.put(Protocol.AMQP_0_8, ProtocolVersion.v0_8);
+        protocolVersionMap.put(Protocol.AMQP_0_9, ProtocolVersion.v0_9);
+        protocolVersionMap.put(Protocol.AMQP_0_9_1, ProtocolVersion.v0_91);
+
+        PROTOCOL_VERSION_MAP = Collections.unmodifiableMap(protocolVersionMap);
+    }
+
+    private static final int TRANSFER_SESSION_ID = 0;
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OutboundConnection_0_8.class);
+
+    private final Protocol _protocol;
+    private final RemoteHost<?> _remoteHost;
+    private final RemoteHostAddress<?> _address;
+    private final VirtualHost<?> _virtualHost;
+
+    private final FederationDecoder _decoder;
+
+
+    private final AggregateTicker _aggregateTicker;
+    private final ProtocolVersion _protocolVersion;
+
+    private final MethodRegistry _methodRegistry;
+    private volatile long _lastReadTime;
+    private volatile long _lastWriteTime;
+    private SchedulableConnection _connection;
+    private volatile AccessControlContext _accessControllerContext;
+
+
+
+    private final AtomicBoolean _stateChanged = new AtomicBoolean();
+    private final AtomicReference<Action<ProtocolEngine>> _workListener = new AtomicReference<>();
+    private volatile Thread _ioThread;
+    private final List<Runnable> _pendingTasks = new CopyOnWriteArrayList<>();
+    private int _classId;
+    private int _methodId;
+    private SaslClient _saslClient;
+    private int _maxFrameSize;
+    private int _maxNoOfChannels;
+
+    private static final OutboundChannel[] _channels = new OutboundChannel[3];
+    private Action<Boolean> _onClosedTask;
+
+    enum State
+    {
+        INIT,
+        AWAIT_START,
+        AWAIT_SECURE,
+        AWAIT_TUNE,
+        AWAIT_OPEN_OK,
+        OPEN,
+        AWAIT_CLOSE_OK,
+        CLOSED
+    }
+
+    private State _state = State.INIT;
+
+
+    public OutboundConnection_0_8(final RemoteHostAddress<?> address,
+                                  final VirtualHost<?> virtualHost,
+                                  final Protocol protocol,
+                                  final byte[] protocolHeader)
+    {
+        _address = address;
+        _protocol = protocol;
+        _virtualHost = virtualHost;
+        _aggregateTicker = new AggregateTicker();
+        _remoteHost = address.getParent(RemoteHost.class);
+        _decoder = new FederationDecoder(this);
+        _protocolVersion = PROTOCOL_VERSION_MAP.get(protocol);
+        _methodRegistry = new MethodRegistry(_protocolVersion);
+
+        _pendingTasks.add(new Runnable()
+        {
+            @Override
+            public void run()
+            {
+                changeState(State.INIT, State.AWAIT_START);
+                _connection.send(QpidByteBuffer.wrap(protocolHeader));
+            }
+        });
+        _stateChanged.set(true);
+    }
+
+
+    public VirtualHost<?> getVirtualHost()
+    {
+        return _virtualHost;
+    }
+
+
+    private synchronized void changeState(final State currentState, final State newState)
+    {
+        if(_state != currentState)
+        {
+            throw new ConnectionScopedRuntimeException("Incorrect state");
+        }
+        _state = newState;
+    }
+
+    private synchronized void assertState(final State currentState)
+    {
+        if (_state != currentState)
+        {
+            throw new ConnectionScopedRuntimeException("Incorrect state");
+        }
+    }
+
+    public Protocol getProtocol()
+    {
+        return _protocol;
+    }
+
+    @Override
+    public final AggregateTicker getAggregateTicker()
+    {
+        return _aggregateTicker;
+    }
+
+    public final Date getLastIoTime()
+    {
+        return new Date(Math.max(getLastReadTime(), getLastWriteTime()));
+    }
+
+    @Override
+    public final long getLastReadTime()
+    {
+        return _lastReadTime;
+    }
+
+    public final void updateLastReadTime()
+    {
+        _lastReadTime = System.currentTimeMillis();
+    }
+
+    @Override
+    public final long getLastWriteTime()
+    {
+        return _lastWriteTime;
+    }
+
+    public final void updateLastWriteTime()
+    {
+        _lastWriteTime = System.currentTimeMillis();
+    }
+
+
+    MethodRegistry getMethodRegistry()
+    {
+        return _methodRegistry;
+    }
+
+
+    @Override
+    public void closed()
+    {
+        Action<Boolean> task = _onClosedTask;
+        if(task != null)
+        {
+            task.performAction(_state == State.OPEN);
+        }
+    }
+
+    public synchronized void writerIdle()
+    {
+        writeFrame(HeartbeatBody.FRAME);
+    }
+
+    @Override
+    public void readerIdle()
+    {
+
+    }
+
+    @Override
+    public Subject getSubject()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean isTransportBlockedForWriting()
+    {
+        return false;
+    }
+
+    @Override
+    public void setTransportBlockedForWriting(final boolean blocked)
+    {
+
+    }
+
+    @Override
+    public void setMessageAssignmentSuspended(final boolean value, final boolean notifyConsumers)
+    {
+
+    }
+
+    @Override
+    public boolean isMessageAssignmentSuspended()
+    {
+        return false;
+    }
+
+
+    @Override
+    public Iterator<Runnable> processPendingIterator()
+    {
+        if (!isIOThread())
+        {
+            return Collections.emptyIterator();
+        }
+        return new ProcessPendingIterator();
+    }
+
+    @Override
+    public boolean hasWork()
+    {
+        return _stateChanged.get();
+    }
+
+    @Override
+    public void notifyWork()
+    {
+        _stateChanged.set(true);
+
+        final Action<ProtocolEngine> listener = _workListener.get();
+        if(listener != null)
+        {
+
+            listener.performAction(this);
+        }
+    }
+
+    @Override
+    public void clearWork()
+    {
+        _stateChanged.set(false);
+    }
+
+    @Override
+    public void setWorkListener(final Action<ProtocolEngine> listener)
+    {
+        _workListener.set(listener);
+    }
+
+
+    @Override
+    public void encryptedTransport()
+    {
+
+    }
+
+    @Override
+    public void received(final QpidByteBuffer msg)
+    {
+        AccessController.doPrivileged(new PrivilegedAction<Void>()
+        {
+            @Override
+            public Void run()
+            {
+                updateLastReadTime();
+
+                try
+                {
+                    _decoder.decodeBuffer(msg);
+                    receivedComplete();
+                }
+                catch (AMQFrameDecodingException | IOException e)
+                {
+                    LOGGER.error("Unexpected exception", e);
+                    throw new ConnectionScopedRuntimeException(e);
+                }
+                catch (StoreException e)
+                {
+                    if (_virtualHost.isActive())
+                    {
+                        throw new ServerScopedRuntimeException(e);
+                    }
+                    else
+                    {
+                        throw new ConnectionScopedRuntimeException(e);
+                    }
+                }
+                return null;
+            }
+        }, getAccessControllerContext());
+
+
+    }
+
+    private void receivedComplete()
+    {
+        for(OutboundChannel channel : _channels)
+        {
+            if (channel != null)
+            {
+                channel.receivedComplete();
+            }
+        }
+    }
+
+
+    public AccessControlContext getAccessControllerContext()
+    {
+        return _accessControllerContext;
+    }
+
+    public final void updateAccessControllerContext()
+    {
+        _accessControllerContext = getAccessControlContextFromSubject(
+                getSubject());
+    }
+
+    public final AccessControlContext getAccessControlContextFromSubject(final Subject subject)
+    {
+        final AccessControlContext acc = AccessController.getContext();
+        return AccessController.doPrivileged(
+                new PrivilegedAction<AccessControlContext>()
+                {
+                    public AccessControlContext run()
+                    {
+                        if (subject == null)
+                            return new AccessControlContext(acc, null);
+                        else
+                            return new AccessControlContext
+                                    (acc,
+                                     new SubjectDomainCombiner(subject));
+                    }
+                });
+    }
+
+
+    @Override
+    public void setIOThread(final Thread ioThread)
+    {
+        _ioThread = ioThread;
+    }
+
+    public boolean isIOThread()
+    {
+        return Thread.currentThread() == _ioThread;
+    }
+
+
+    @Override
+    public void setConnection(final SchedulableConnection connection)
+    {
+        _connection = connection;
+    }
+
+    @Override
+    public void setOnClosedTask(final Action<Boolean> onClosedTask)
+    {
+        _onClosedTask = onClosedTask;
+    }
+
+    @Override
+    public ProtocolVersion getProtocolVersion()
+    {
+        return _protocolVersion;
+    }
+
+    @Override
+    public ClientChannelMethodProcessor getChannelMethodProcessor(final int channelId)
+    {
+        return getChannel(channelId);
+    }
+
+
+    public OutboundChannel getChannel(final int channelId)
+    {
+        return channelId < _channels.length ? _channels[channelId] : null;
+    }
+
+    public void setMaxFrameSize(int frameMax)
+    {
+        _maxFrameSize = frameMax;
+        _decoder.setMaxFrameSize(frameMax);
+    }
+
+    public int getMaxFrameSize()
+    {
+        return _maxFrameSize;
+    }
+
+    @Override
+    public void receiveConnectionClose(final int replyCode,
+                                       final AMQShortString replyText,
+                                       final int classId,
+                                       final int methodId)
+    {
+
+        writeFrame(_methodRegistry.createConnectionCloseOkBody().generateFrame(0));
+        _connection.close();
+    }
+
+    @Override
+    public void receiveConnectionCloseOk()
+    {
+        // TODO
+    }
+
+    @Override
+    public void receiveHeartbeat()
+    {
+    }
+
+    @Override
+    public void receiveProtocolHeader(final ProtocolInitiation protocolInitiation)
+    {
+        _connection.close();
+    }
+
+    @Override
+    public void setCurrentMethod(final int classId, final int methodId)
+    {
+        _classId = classId;
+        _methodId = methodId;
+    }
+
+    void writeFrame(AMQDataBlock frame)
+    {
+        LOGGER.debug("SEND: {}", frame);
+
+
+        frame.writePayload(_connection);
+
+
+        updateLastWriteTime();
+
+    }
+
+
+    @Override
+    public boolean ignoreAllButCloseOk()
+    {
+        // TODO
+        return false;
+    }
+
+    @Override
+    public void receiveConnectionStart(final short versionMajor,
+                                       final short versionMinor,
+                                       final FieldTable serverProperties,
+                                       final byte[] mechanisms,
+                                       final byte[] locales)
+    {
+        changeState(State.AWAIT_START, State.AWAIT_SECURE);
+        List<String> saslMechanisms = Arrays.asList(new String(mechanisms, StandardCharsets.UTF_8).split(" "));
+        Map propMap = FieldTable.convertToMap(serverProperties);
+
+        Collection<Credential> credentialList = _remoteHost.getChildren(Credential.class);
+
+        SaslClient client = null;
+        for(Credential<?> credentials : credentialList)
+        {
+            client = credentials.getSaslClient(saslMechanisms);
+            if(client != null)
+            {
+                break;
+            }
+        }
+
+        if(client != null)
+        {
+            _saslClient = client;
+            try
+            {
+                byte[] initialResponse = client.hasInitialResponse() ? client.evaluateChallenge(new byte[0]) : new byte[0];
+
+                FieldTable clientProperties = FieldTableFactory.newFieldTable();
+                clientProperties.setString(ServerPropertyNames.PRODUCT,
+                                           CommonProperties.getProductName());
+                clientProperties.setString(ServerPropertyNames.VERSION,
+                                           CommonProperties.getReleaseVersion());
+                clientProperties.setString(ServerPropertyNames.QPID_BUILD,
+                                           CommonProperties.getBuildVersion());
+                clientProperties.setString(ServerPropertyNames.QPID_INSTANCE_NAME,
+                                           _virtualHost.getName());
+
+
+                writeFrame(_methodRegistry.createConnectionStartOkBody(clientProperties, AMQShortString.valueOf(_saslClient.getMechanismName()), initialResponse, null).generateFrame(0));
+                if(client.isComplete())
+                {
+                    changeState(State.AWAIT_SECURE, State.AWAIT_TUNE);
+                }
+            }
+            catch (SaslException e)
+            {
+                throw new ConnectionScopedRuntimeException(e);
+            }
+        }
+        else
+        {
+            throw new ConnectionScopedRuntimeException("Unable to find acceptable sasl mechanism");
+        }
+
+    }
+
+    @Override
+    public void receiveConnectionSecure(final byte[] challenge)
+    {
+        assertState(State.AWAIT_SECURE);
+        try
+        {
+            byte[] response = _saslClient.evaluateChallenge(challenge);
+
+            writeFrame(_methodRegistry.createConnectionSecureOkBody(response).generateFrame(0));
+            if(_saslClient.isComplete())
+            {
+                changeState(State.AWAIT_SECURE, State.AWAIT_TUNE);
+            }
+        }
+        catch (SaslException e)
+        {
+            throw new ConnectionScopedRuntimeException(e);
+        }
+    }
+
+    @Override
+    public void receiveConnectionRedirect(final AMQShortString host, final AMQShortString knownHosts)
+    {
+        LOGGER.info("Connection redirect to {} received, however redirection is not followed for federation links");
+        _connection.close();
+    }
+
+    private int getDefaultMaxFrameSize()
+    {
+        Broker<?> broker = _virtualHost.getBroker();
+
+        return broker.getNetworkBufferSize();
+    }
+
+    protected void initialiseHeartbeating(final long writerDelay, final long readerDelay)
+    {
+        if (writerDelay > 0)
+        {
+            _aggregateTicker.addTicker(new ServerIdleWriteTimeoutTicker(this, (int) writerDelay));
+            _connection.setMaxWriteIdleMillis(writerDelay);
+        }
+
+        if (readerDelay > 0)
+        {
+            _aggregateTicker.addTicker(new ServerIdleReadTimeoutTicker(_connection, this, (int) readerDelay));
+            _connection.setMaxReadIdleMillis(readerDelay);
+        }
+    }
+
+
+
+    public int getMaximumNumberOfChannels()
+    {
+        return _maxNoOfChannels;
+    }
+
+    private void setMaximumNumberOfChannels(int value)
+    {
+        _maxNoOfChannels = value;
+    }
+
+
+    @Override
+    public void receiveConnectionTune(final int channelMax, final long frameMax, final int heartbeat)
+    {
+        assertState(State.AWAIT_TUNE);
+
+        final int desiredHeartbeatInterval = _address.getDesiredHeartbeatInterval();
+        int heartbeatDelay = heartbeat == 0
+                ? desiredHeartbeatInterval
+                : (desiredHeartbeatInterval == 0) ? heartbeat : Math.min(heartbeat, desiredHeartbeatInterval);
+
+        long writerDelay = 1000L * heartbeatDelay;
+        long readerDelay = 1000L * BrokerProperties.HEARTBEAT_TIMEOUT_FACTOR * heartbeatDelay;
+        initialiseHeartbeating(writerDelay, readerDelay);
+
+        int maxFrameSize = getDefaultMaxFrameSize();
+        if (maxFrameSize <= 0)
+        {
+            maxFrameSize = Integer.MAX_VALUE;
+        }
+
+        if (frameMax > 0 && frameMax < maxFrameSize)
+        {
+            maxFrameSize = (int) frameMax;
+        }
+
+        setMaxFrameSize(maxFrameSize);
+
+        //0 means no implied limit, except that forced by protocol limitations (0xFFFF)
+        setMaximumNumberOfChannels( ((channelMax == 0l) || (channelMax > 0xFFFFL))
+                                            ? 0xFFFF
+                                            : (int)channelMax);
+
+
+
+        writeFrame(_methodRegistry.createConnectionTuneOkBody(_maxNoOfChannels, maxFrameSize, heartbeatDelay).generateFrame(0));
+        writeFrame(_methodRegistry.createConnectionOpenBody(AMQShortString.valueOf(_address.getHostName()), AMQShortString.EMPTY_STRING, false).generateFrame(0));
+
+        changeState(State.AWAIT_TUNE, State.AWAIT_OPEN_OK);
+
+
+    }
+
+    @Override
+    public void receiveConnectionOpenOk(final AMQShortString knownHosts)
+    {
+        changeState(State.AWAIT_OPEN_OK, State.OPEN);
+
+        createTransferSession();
+
+    }
+
+    private void createTransferSession()
+    {
+        _channels[TRANSFER_SESSION_ID] = new TransferSession_0_8(TRANSFER_SESSION_ID, this);
+    }
+
+
+    private class ProcessPendingIterator implements Iterator<Runnable>
+    {
+        private final List<OutboundChannel> _sessionsWithPending;
+        private Iterator<OutboundChannel> _sessionIterator;
+        private ProcessPendingIterator()
+        {
+            _sessionsWithPending = new ArrayList<>();
+            for(OutboundChannel channel : _channels)
+            {
+                if(channel != null)
+                {
+                    _sessionsWithPending.add(channel);
+                }
+            }
+            _sessionIterator = _sessionsWithPending.iterator();
+        }
+
+        @Override
+        public boolean hasNext()
+        {
+            return !(_sessionsWithPending.isEmpty() && _pendingTasks.isEmpty());
+        }
+
+        @Override
+        public Runnable next()
+        {
+            if(!_sessionsWithPending.isEmpty())
+            {
+                if(!_sessionIterator.hasNext())
+                {
+                    _sessionIterator = _sessionsWithPending.iterator();
+                }
+                final OutboundChannel session = _sessionIterator.next();
+                return new Runnable()
+                {
+                    @Override
+                    public void run()
+                    {
+                        if(!session.processPending())
+                        {
+                            _sessionIterator.remove();
+                        }
+                    }
+                };
+            }
+            else if(!_pendingTasks.isEmpty())
+            {
+                return _pendingTasks.remove(0);
+            }
+            else
+            {
+                throw new NoSuchElementException();
+            }
+        }
+
+        @Override
+        public void remove()
+        {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_8.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_8.java
new file mode 100644
index 0000000..b8af4ff
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_8.java
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import org.apache.qpid.server.federation.OutboundProtocolEngine;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.plugin.OutboundProtocolEngineCreator;
+import org.apache.qpid.server.plugin.PluggableService;
+
+@PluggableService
+public class OutboundProtocolEngineCreator_0_8 implements OutboundProtocolEngineCreator
+{
+
+    private static final byte[] AMQP_0_8_HEADER =
+            new byte[] { (byte) 'A',
+                         (byte) 'M',
+                         (byte) 'Q',
+                         (byte) 'P',
+                         (byte) 1,
+                         (byte) 1,
+                         (byte) 8,
+                         (byte) 0
+            };
+
+    public OutboundProtocolEngineCreator_0_8()
+    {
+    }
+
+    public Protocol getVersion()
+    {
+        return Protocol.AMQP_0_8;
+    }
+
+    @Override
+    public OutboundProtocolEngine newProtocolEngine(final RemoteHostAddress<?> address, final VirtualHost<?> virtualHost)
+    {
+        return new OutboundConnection_0_8(address, virtualHost, Protocol.AMQP_0_8, AMQP_0_8_HEADER);
+    }
+
+    @Override
+    public String getType()
+    {
+        return getVersion().toString();
+    }
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_9.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_9.java
new file mode 100644
index 0000000..2854a42
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_9.java
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import org.apache.qpid.server.federation.OutboundProtocolEngine;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.plugin.OutboundProtocolEngineCreator;
+import org.apache.qpid.server.plugin.PluggableService;
+
+@PluggableService
+public class OutboundProtocolEngineCreator_0_9 implements OutboundProtocolEngineCreator
+{
+
+    private static final byte[] AMQP_0_9_HEADER =
+            new byte[] { (byte) 'A',
+                         (byte) 'M',
+                         (byte) 'Q',
+                         (byte) 'P',
+                         (byte) 1,
+                         (byte) 1,
+                         (byte) 0,
+                         (byte) 9
+            };
+
+    public OutboundProtocolEngineCreator_0_9()
+    {
+    }
+
+    public Protocol getVersion()
+    {
+        return Protocol.AMQP_0_9;
+    }
+
+    @Override
+    public OutboundProtocolEngine newProtocolEngine(final RemoteHostAddress<?> address, final VirtualHost<?> virtualHost)
+    {
+        return new OutboundConnection_0_8(address, virtualHost, Protocol.AMQP_0_9, AMQP_0_9_HEADER);
+    }
+
+    @Override
+    public String getType()
+    {
+        return getVersion().toString();
+    }
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_9_1.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_9_1.java
new file mode 100644
index 0000000..87f7cd0
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/OutboundProtocolEngineCreator_0_9_1.java
@@ -0,0 +1,65 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import org.apache.qpid.server.federation.OutboundProtocolEngine;
+import org.apache.qpid.server.model.Protocol;
+import org.apache.qpid.server.model.RemoteHostAddress;
+import org.apache.qpid.server.model.VirtualHost;
+import org.apache.qpid.server.plugin.OutboundProtocolEngineCreator;
+import org.apache.qpid.server.plugin.PluggableService;
+
+@PluggableService
+public class OutboundProtocolEngineCreator_0_9_1 implements OutboundProtocolEngineCreator
+{
+
+    private static final byte[] AMQP_0_9_1_HEADER =
+            new byte[] { (byte) 'A',
+                         (byte) 'M',
+                         (byte) 'Q',
+                         (byte) 'P',
+                         (byte) 0,
+                         (byte) 0,
+                         (byte) 9,
+                         (byte) 1
+            };
+
+    public OutboundProtocolEngineCreator_0_9_1()
+    {
+    }
+
+    public Protocol getVersion()
+    {
+        return Protocol.AMQP_0_9_1;
+    }
+
+    @Override
+    public OutboundProtocolEngine newProtocolEngine(final RemoteHostAddress<?> address, final VirtualHost<?> virtualHost)
+    {
+        return new OutboundConnection_0_8(address, virtualHost, Protocol.AMQP_0_9_1, AMQP_0_9_1_HEADER);
+    }
+
+    @Override
+    public String getType()
+    {
+        return getVersion().toString();
+    }
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/TransferSession_0_8.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/TransferSession_0_8.java
new file mode 100644
index 0000000..b5d86cc
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/TransferSession_0_8.java
@@ -0,0 +1,721 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import java.security.AccessControlContext;
+import java.util.Collection;
+import java.util.EnumMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Queue;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import java.util.concurrent.TimeoutException;
+
+import com.google.common.util.concurrent.AbstractFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.framing.AMQBody;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.BasicContentHeaderProperties;
+import org.apache.qpid.framing.BasicGetOkBody;
+import org.apache.qpid.framing.ConfirmSelectBody;
+import org.apache.qpid.framing.ConfirmSelectOkBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.FieldTable;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.plugin.MessageConverter;
+import org.apache.qpid.server.protocol.MessageConverterRegistry;
+import org.apache.qpid.server.protocol.v0_8.AMQMessage;
+import org.apache.qpid.server.protocol.v0_8.MessageContentSourceBody;
+import org.apache.qpid.server.transfer.TransferQueueConsumer;
+import org.apache.qpid.server.transfer.TransferQueueEntry;
+import org.apache.qpid.server.txn.LocalTransaction;
+import org.apache.qpid.server.txn.ServerTransaction;
+import org.apache.qpid.server.util.ConnectionScopedRuntimeException;
+
+class TransferSession_0_8 implements OutboundChannel
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(TransferSession_0_8.class);
+    private static final Runnable NO_OP = new Runnable()
+    {
+        @Override
+        public void run()
+        {
+
+        }
+    };
+
+    private final OutboundConnection_0_8 _connection;
+    private final int _channelId;
+    private final MethodRegistry _methodRegistry;
+    private final LocalTransaction _txn;
+    private Collection<String> _remoteHostGlobalDomains;
+    private TransferTarget_0_8 _target;
+    private TransferQueueConsumer _consumer;
+    private final SortedMap<Long, TransferQueueEntry> _unconfirmed = new TreeMap<>();
+    private volatile boolean _flowControlled;
+    private volatile long _lastSent = -0L;
+
+    private int _maxUnconfirmed = 200;
+
+    enum Operation {
+        EXCHANGE_DECLARE,
+        EXCHANGE_DELETE,
+        EXCHANGE_BOUND,
+        QUEUE_BIND,
+        QUEUE_UNBIND,
+        QUEUE_DECLARE,
+        QUEUE_DELETE,
+        QUEUE_PURGE,
+        BASIC_RECOVER_SYNC,
+        BAISC_QOS,
+        BASIC_CONSUME,
+        BASIC_CANCEL,
+        TX_SELECT,
+        TX_COMMIT,
+        TX_ROLLBACK,
+        CHANNEL_FLOW,
+        CONFIRM_SELECT,
+        ACK,
+        BASIC_GET
+    }
+
+    private static final class TimedSettableFuture<V> extends AbstractFuture<V>
+    {
+        private final long _timeoutTime;
+
+        private TimedSettableFuture(final long timeoutTime)
+        {
+            _timeoutTime = timeoutTime;
+        }
+
+        public boolean set(V value)
+        {
+            return super.set(value);
+        }
+
+        @Override
+        public boolean setException(Throwable throwable)
+        {
+            return super.setException(throwable);
+        }
+
+        public long getTimeoutTime()
+        {
+            return _timeoutTime;
+        }
+
+        public boolean checkTimeout(long time)
+        {
+            if(time > _timeoutTime)
+            {
+                setException(new TimeoutException("Timed out waiting for response"));
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
+
+    private final Map<Operation, Queue<TimedSettableFuture<AMQMethodBody>>> _synchronousOperationListeners = new EnumMap<>(Operation.class);
+
+    {
+        for(Operation op : Operation.values())
+        {
+            _synchronousOperationListeners.put(op, new LinkedList<TimedSettableFuture<AMQMethodBody>>());
+        }
+    }
+
+    enum State { AWAITING_OPEN, OPEN, AWAITING_CLOSE_OK }
+
+    private State _state = State.AWAITING_OPEN;
+
+    private interface MessageHandler
+    {
+        void receiveMessageHeader(BasicContentHeaderProperties properties, long bodySize);
+
+        void receiveMessageContent(QpidByteBuffer data);
+    }
+
+
+    private final MessageHandler _unexpectedMessageHandler = new MessageHandler()
+    {
+        @Override
+        public void receiveMessageHeader(final BasicContentHeaderProperties properties, final long bodySize)
+        {
+            throw new ConnectionScopedRuntimeException("Unexpected frame");
+        }
+
+        @Override
+        public void receiveMessageContent(final QpidByteBuffer data)
+        {
+            throw new ConnectionScopedRuntimeException("Unexpected frame");
+        }
+    };
+
+    private volatile MessageHandler _messageHandler = _unexpectedMessageHandler;
+
+
+    TransferSession_0_8(final int channelId, final OutboundConnection_0_8 outboundConnection)
+    {
+        _connection = outboundConnection;
+        _channelId = channelId;
+        _methodRegistry = outboundConnection.getMethodRegistry();
+        writeMethod(_methodRegistry.createChannelOpenBody(AMQShortString.EMPTY_STRING));
+        _txn = new LocalTransaction(outboundConnection.getVirtualHost().getMessageStore());
+    }
+
+    private synchronized void changeState(final State currentState, final State newState)
+    {
+        if(_state != currentState)
+        {
+            throw new ConnectionScopedRuntimeException("Incorrect state");
+        }
+        _state = newState;
+    }
+
+    private synchronized void assertState(final State currentState)
+    {
+        if (_state != currentState)
+        {
+            throw new ConnectionScopedRuntimeException("Incorrect state");
+        }
+    }
+
+
+    @Override
+    public void receiveChannelOpenOk()
+    {
+        changeState(State.AWAITING_OPEN, State.OPEN);
+
+        writeMethod(new ConfirmSelectBody(true));
+
+        writeMethod(_methodRegistry.createBasicGetBody(0, AMQShortString.valueOf("$virtualhostProperties"), true));
+        final FutureCallback<AMQMethodBody> callback = new FutureCallback<AMQMethodBody>()
+        {
+            @Override
+            public void onSuccess(final AMQMethodBody result)
+            {
+                if (result instanceof BasicGetOkBody)
+                {
+                    _messageHandler = new VirtualHostPropertiesHandler();
+                }
+                else
+                {
+                    throw new ConnectionScopedRuntimeException("Unable to determine virtual host properties from remote host");
+                }
+            }
+
+            @Override
+            public void onFailure(final Throwable t)
+            {
+                if(t instanceof RuntimeException)
+                {
+                    throw ((RuntimeException)t);
+                }
+                else
+                {
+                    throw new ConnectionScopedRuntimeException(t);
+                }
+            }
+        };
+        addOperationResponse(Operation.BASIC_GET, callback);
+    }
+
+    private void addOperationResponse(Operation operation, FutureCallback<AMQMethodBody> callback)
+    {
+        final TimedSettableFuture<AMQMethodBody> future =
+                new TimedSettableFuture<>(System.currentTimeMillis() + 30000L);
+        Futures.addCallback(future, callback);
+        _synchronousOperationListeners.get(operation).add(future);
+    }
+
+    private void performOperationResponse(Operation operation, AMQMethodBody body)
+    {
+        final TimedSettableFuture<AMQMethodBody> future = _synchronousOperationListeners.get(operation).poll();
+
+        if(future == null)
+        {
+            throw new ConnectionScopedRuntimeException("Unexpected frame ");
+        }
+        else
+        {
+            future.set(body);
+        }
+    }
+
+
+    private void setRemoteHostGlobalDomains(final Collection<String> remoteHostGlobalDomains)
+    {
+        LOGGER.debug("Setting remote host global domains: {}", remoteHostGlobalDomains);
+        _remoteHostGlobalDomains = remoteHostGlobalDomains;
+
+        _target = new TransferTarget_0_8(this, remoteHostGlobalDomains);
+        _consumer = _connection.getVirtualHost().getTransferQueue().addConsumer(_target, "consumer");
+    }
+
+
+
+    @Override
+    public void receiveChannelAlert(final int replyCode, final AMQShortString replyText, final FieldTable details)
+    {
+
+    }
+
+    @Override
+    public void receiveAccessRequestOk(final int ticket)
+    {
+
+    }
+
+    @Override
+    public void receiveExchangeDeclareOk()
+    {
+        performOperationResponse(Operation.EXCHANGE_DECLARE, _methodRegistry.createExchangeDeclareOkBody());
+    }
+
+    @Override
+    public void receiveExchangeDeleteOk()
+    {
+        performOperationResponse(Operation.EXCHANGE_DELETE, _methodRegistry.createExchangeDeleteOkBody());
+    }
+
+    @Override
+    public void receiveExchangeBoundOk(final int replyCode, final AMQShortString replyText)
+    {
+        performOperationResponse(Operation.EXCHANGE_BOUND, _methodRegistry.createExchangeBoundOkBody(replyCode, replyText));
+    }
+
+    @Override
+    public void receiveQueueBindOk()
+    {
+        performOperationResponse(Operation.QUEUE_BIND, _methodRegistry.createQueueBindOkBody());
+    }
+
+    @Override
+    public void receiveQueueUnbindOk()
+    {
+        performOperationResponse(Operation.QUEUE_UNBIND, _methodRegistry.createQueueUnbindOkBody());
+    }
+
+    @Override
+    public void receiveQueueDeclareOk(final AMQShortString queue, final long messageCount, final long consumerCount)
+    {
+        performOperationResponse(Operation.QUEUE_DECLARE, _methodRegistry.createQueueDeclareOkBody(queue, messageCount, consumerCount));
+    }
+
+    @Override
+    public void receiveQueuePurgeOk(final long messageCount)
+    {
+        performOperationResponse(Operation.QUEUE_PURGE, _methodRegistry.createQueuePurgeOkBody(messageCount));
+
+    }
+
+    @Override
+    public void receiveQueueDeleteOk(final long messageCount)
+    {
+        performOperationResponse(Operation.QUEUE_DELETE, _methodRegistry.createQueueDeleteOkBody(messageCount));
+
+    }
+
+    @Override
+    public void receiveBasicRecoverSyncOk()
+    {
+        performOperationResponse(Operation.BASIC_RECOVER_SYNC, _methodRegistry.createBasicRecoverSyncOkBody());
+    }
+
+    @Override
+    public void receiveBasicQosOk()
+    {
+        performOperationResponse(Operation.BAISC_QOS, _methodRegistry.createBasicQosOkBody());
+    }
+
+    @Override
+    public void receiveBasicConsumeOk(final AMQShortString consumerTag)
+    {
+        performOperationResponse(Operation.BASIC_CONSUME, _methodRegistry.createBasicConsumeOkBody(consumerTag));
+    }
+
+    @Override
+    public void receiveBasicCancelOk(final AMQShortString consumerTag)
+    {
+        performOperationResponse(Operation.BASIC_CANCEL, _methodRegistry.createBasicCancelOkBody(consumerTag));
+    }
+
+    @Override
+    public void receiveBasicReturn(final int replyCode,
+                                   final AMQShortString replyText,
+                                   final AMQShortString exchange,
+                                   final AMQShortString routingKey)
+    {
+
+    }
+
+    @Override
+    public void receiveBasicDeliver(final AMQShortString consumerTag,
+                                    final long deliveryTag,
+                                    final boolean redelivered,
+                                    final AMQShortString exchange,
+                                    final AMQShortString routingKey)
+    {
+
+    }
+
+    @Override
+    public void receiveBasicGetOk(final long deliveryTag,
+                                  final boolean redelivered,
+                                  final AMQShortString exchange,
+                                  final AMQShortString routingKey,
+                                  final long messageCount)
+    {
+        performOperationResponse(Operation.BASIC_GET, _methodRegistry.createBasicGetOkBody(deliveryTag, redelivered, exchange, routingKey, messageCount));
+    }
+
+    @Override
+    public void receiveBasicGetEmpty()
+    {
+        performOperationResponse(Operation.BASIC_GET, _methodRegistry.createBasicGetEmptyBody(AMQShortString.EMPTY_STRING));
+    }
+
+    @Override
+    public void receiveTxSelectOk()
+    {
+        performOperationResponse(Operation.TX_SELECT, _methodRegistry.createTxSelectOkBody());
+    }
+
+    @Override
+    public void receiveTxCommitOk()
+    {
+        performOperationResponse(Operation.TX_COMMIT, _methodRegistry.createTxCommitOkBody());
+    }
+
+    @Override
+    public void receiveTxRollbackOk()
+    {
+        performOperationResponse(Operation.TX_ROLLBACK, _methodRegistry.createTxRollbackOkBody());
+    }
+
+    @Override
+    public void receiveConfirmSelectOk()
+    {
+        performOperationResponse(Operation.CONFIRM_SELECT, ConfirmSelectOkBody.INSTANCE);
+    }
+
+    @Override
+    public void receiveChannelFlow(final boolean active)
+    {
+        _flowControlled = !active;
+        writeMethod(_methodRegistry.createChannelFlowOkBody(active));
+
+    }
+
+    @Override
+    public void receiveChannelFlowOk(final boolean active)
+    {
+        performOperationResponse(Operation.CHANNEL_FLOW, _methodRegistry.createChannelFlowOkBody(active));
+    }
+
+    @Override
+    public void receiveChannelClose(final int replyCode,
+                                    final AMQShortString replyText,
+                                    final int classId,
+                                    final int methodId)
+    {
+
+    }
+
+    @Override
+    public void receiveChannelCloseOk()
+    {
+    }
+
+    @Override
+    public void receiveMessageContent(final QpidByteBuffer data)
+    {
+        _messageHandler.receiveMessageContent(data);
+    }
+
+    @Override
+    public void receiveMessageHeader(final BasicContentHeaderProperties properties, final long bodySize)
+    {
+        _messageHandler.receiveMessageHeader(properties, bodySize);
+    }
+
+    @Override
+    public boolean ignoreAllButCloseOk()
+    {
+        return false;
+    }
+
+    @Override
+    public void receiveBasicNack(final long deliveryTag, final boolean multiple, final boolean requeue)
+    {
+        if(multiple)
+        {
+            Iterator<Map.Entry<Long, TransferQueueEntry>> iter = _unconfirmed.entrySet().iterator();
+            while(iter.hasNext())
+            {
+                Map.Entry<Long, TransferQueueEntry> pair = iter.next();
+                if(pair.getKey() > deliveryTag)
+                {
+                    break;
+                }
+                else
+                {
+                    final TransferQueueEntry entry = pair.getValue();
+
+                    if(requeue)
+                    {
+                        entry.release();
+                    }
+                    else
+                    {
+                        _txn.dequeue(entry.getEnqueueRecord(), new ServerTransaction.Action()
+                        {
+                            @Override
+                            public void postCommit()
+                            {
+                                entry.delete();
+                            }
+
+                            @Override
+                            public void onRollback()
+                            {
+                                entry.release();
+                            }
+                        });
+
+                    }
+                }
+            }
+        }
+        else
+        {
+            final TransferQueueEntry entry = _unconfirmed.remove(deliveryTag);
+            if(requeue)
+            {
+                entry.release();
+            }
+            else
+            {
+                _txn.dequeue(entry.getEnqueueRecord(), new ServerTransaction.Action()
+                {
+                    @Override
+                    public void postCommit()
+                    {
+                        entry.delete();
+                    }
+
+                    @Override
+                    public void onRollback()
+                    {
+                        entry.release();
+                    }
+                });
+            }
+        }
+    }
+
+    @Override
+    public void receiveBasicAck(final long deliveryTag, final boolean multiple)
+    {
+        if(multiple)
+        {
+            Iterator<Map.Entry<Long, TransferQueueEntry>> iter = _unconfirmed.entrySet().iterator();
+            while(iter.hasNext())
+            {
+                Map.Entry<Long, TransferQueueEntry> pair = iter.next();
+                if(pair.getKey() > deliveryTag)
+                {
+                    break;
+                }
+                else
+                {
+                    final TransferQueueEntry entry = pair.getValue();
+                    _txn.dequeue(entry.getEnqueueRecord(), new ServerTransaction.Action()
+                    {
+                        @Override
+                        public void postCommit()
+                        {
+                            entry.delete();
+                        }
+
+                        @Override
+                        public void onRollback()
+                        {
+                            entry.release();
+                        }
+                    });
+                }
+            }
+        }
+        else
+        {
+            final TransferQueueEntry entry = _unconfirmed.remove(deliveryTag);
+            _txn.dequeue(entry.getEnqueueRecord(), new ServerTransaction.Action()
+            {
+                @Override
+                public void postCommit()
+                {
+                    entry.delete();
+                }
+
+                @Override
+                public void onRollback()
+                {
+                    entry.release();
+                }
+            });
+
+        }
+    }
+
+    boolean isSuspended()
+    {
+        return _flowControlled || _unconfirmed.size() > _maxUnconfirmed;
+    }
+
+    @Override
+    public AccessControlContext getAccessControllerContext()
+    {
+        return null;
+    }
+
+    @Override
+    public boolean processPending()
+    {
+        if(_consumer != null)
+        {
+            return _consumer.processPending();
+        }
+        return false;
+    }
+
+    void notifyWork()
+    {
+        _connection.notifyWork();
+    }
+
+    @Override
+    public void receivedComplete()
+    {
+        _txn.commitAsync(NO_OP);
+    }
+
+    void writeMethod(AMQMethodBody body)
+    {
+        writeFrame(body.generateFrame(_channelId));
+    }
+
+    void writeFrame(AMQFrame frame)
+    {
+        _connection.writeFrame(frame);
+    }
+
+
+    private class VirtualHostPropertiesHandler implements MessageHandler
+    {
+        private long _remaining;
+        private BasicContentHeaderProperties _properties;
+
+        @Override
+        public void receiveMessageHeader(final BasicContentHeaderProperties properties, final long bodySize)
+        {
+            _remaining = bodySize;
+            _properties = properties;
+            receiveVirtualHostProperties(_properties);
+        }
+
+        @Override
+        public void receiveMessageContent(final QpidByteBuffer data)
+        {
+            if((_remaining -= data.remaining()) == 0l)
+            {
+                _messageHandler = _unexpectedMessageHandler;
+            }
+        }
+    }
+
+    private void receiveVirtualHostProperties(final BasicContentHeaderProperties properties)
+    {
+        Collection<String> remoteHostGlobalDomains =
+                properties.getHeaders().getFieldArray("virtualhost.globalDomains");
+        setRemoteHostGlobalDomains(remoteHostGlobalDomains);
+    }
+
+
+    void transfer(final TransferQueueEntry entry)
+    {
+        ServerMessage message = entry.getMessage();
+        _unconfirmed.put(++_lastSent, entry);
+
+        writeMethod(_methodRegistry.createBasicPublishBody(0, "", message.getInitialRoutingAddress(), false, false));
+        if(!(message instanceof AMQMessage))
+        {
+            final MessageConverter converter =
+                    MessageConverterRegistry.getConverter(message.getClass(), AMQMessage.class);
+            message = converter.convert(message, _connection.getVirtualHost());
+        }
+
+        AMQMessage amqMessage = (AMQMessage) message;
+        ContentHeaderBody contentHeaderBody = amqMessage.getContentHeaderBody();
+        writeHeader(contentHeaderBody);
+
+        int bodySize = (int) contentHeaderBody.getBodySize();
+
+        if (bodySize > 0)
+        {
+            int maxBodySize = (int) _connection.getMaxFrameSize() - AMQFrame.getFrameOverhead();
+
+            int writtenSize = 0;
+
+            while (writtenSize < bodySize)
+            {
+                int capacity = bodySize - writtenSize > maxBodySize ? maxBodySize : bodySize - writtenSize;
+                AMQBody body = new MessageContentSourceBody(message, writtenSize, capacity);
+                writtenSize += capacity;
+
+                writeFrame(new AMQFrame(_channelId, body));
+            }
+        }
+
+    }
+
+
+
+
+
+    private void writeHeader(final ContentHeaderBody headerBody)
+    {
+        _connection.writeFrame(new AMQFrame(_channelId, headerBody));
+    }
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/TransferTarget_0_8.java b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/TransferTarget_0_8.java
new file mode 100644
index 0000000..135714e
--- /dev/null
+++ b/broker-plugins/amqp-0-8-protocol/src/main/java/org/apache/qpid/server/protocol/v0_8/federation/TransferTarget_0_8.java
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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.protocol.v0_8.federation;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.transfer.TransferQueueEntry;
+import org.apache.qpid.server.transfer.TransferTarget;
+
+public class TransferTarget_0_8 implements TransferTarget
+{
+    private final TransferSession_0_8 _session;
+    private final Collection<String> _globalDomains;
+
+    public TransferTarget_0_8(final TransferSession_0_8 transferSession_0_8,
+                              final Collection<String> remoteHostGlobalDomains)
+    {
+        _session = transferSession_0_8;
+        _globalDomains = remoteHostGlobalDomains;
+    }
+
+    @Override
+    public void notifyWork()
+    {
+        _session.notifyWork();
+    }
+
+    @Override
+    public Collection<String> getGlobalAddressDomains()
+    {
+        return Collections.unmodifiableCollection(_globalDomains);
+    }
+
+    @Override
+    public void send(final TransferQueueEntry entry)
+    {
+        _session.transfer(entry);
+    }
+
+    @Override
+    public void restoreCredit(final ServerMessage message)
+    {
+
+    }
+
+    @Override
+    public boolean wouldSuspend(final TransferQueueEntry entry)
+    {
+        return _session.isSuspended();
+    }
+
+    @Override
+    public boolean isSuspended()
+    {
+        return _session.isSuspended();
+    }
+}
diff --git a/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeueTest.java b/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeueTest.java
index 74dccd6..33018b8 100644
--- a/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeueTest.java
+++ b/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/ExtractResendAndRequeueTest.java
@@ -20,23 +20,25 @@
  */
 package org.apache.qpid.server.protocol.v0_8;
 
-import org.apache.qpid.QpidException;
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.message.MessageInstance;
-import org.apache.qpid.server.message.ServerMessage;
-import org.apache.qpid.server.model.Queue;
-import org.apache.qpid.server.queue.QueueEntry;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.Map;
 
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import org.apache.qpid.QpidException;
+import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
+import org.apache.qpid.server.message.ServerMessage;
+import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.queue.QueueEntry;
+import org.apache.qpid.test.utils.QpidTestCase;
 
 /**
  * QPID-1385 : Race condition between added to unacked map and resending due to a rollback.
@@ -62,7 +64,7 @@
     private static final int INITIAL_MSG_COUNT = 10;
     private Queue _queue;
     private LinkedList<MessageInstance> _referenceList = new LinkedList<MessageInstance>();
-    private ConsumerImpl _consumer;
+    private MessageInstanceConsumer _consumer;
     private boolean _queueDeleted;
 
     @Override
@@ -73,8 +75,8 @@
         _queue = mock(Queue.class);
         when(_queue.getName()).thenReturn(getName());
         when(_queue.isDeleted()).thenReturn(_queueDeleted);
-        _consumer = mock(ConsumerImpl.class);
-        when(_consumer.getConsumerNumber()).thenReturn(ConsumerImpl.CONSUMER_NUMBER_GENERATOR.getAndIncrement());
+        _consumer = mock(MessageInstanceConsumer.class);
+        when(_consumer.getIdentifier()).thenReturn(Consumer.CONSUMER_NUMBER_GENERATOR.getAndIncrement());
 
 
         long id = 0;
diff --git a/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/UnacknowledgedMessageMapTest.java b/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/UnacknowledgedMessageMapTest.java
index f70afd6..52a6225 100644
--- a/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/UnacknowledgedMessageMapTest.java
+++ b/broker-plugins/amqp-0-8-protocol/src/test/java/org/apache/qpid/server/protocol/v0_8/UnacknowledgedMessageMapTest.java
@@ -25,13 +25,13 @@
 
 import java.util.Collection;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.test.utils.QpidTestCase;
 
 public class UnacknowledgedMessageMapTest extends QpidTestCase
 {
-    private final ConsumerImpl _consumer = mock(ConsumerImpl.class);
+    private final MessageInstanceConsumer _consumer = mock(MessageInstanceConsumer.class);
 
     public void testDeletedMessagesCantBeAcknowledged()
     {
diff --git a/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java b/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java
index 876f91a..2e9a24c 100644
--- a/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java
+++ b/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/ConsumerTarget_1_0.java
@@ -27,6 +27,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.protocol.v1_0.codec.ValueHandler;
 import org.apache.qpid.server.protocol.v1_0.messaging.SectionEncoder;
 import org.apache.qpid.server.protocol.v1_0.messaging.SectionEncoderImpl;
@@ -49,7 +50,6 @@
 import org.apache.qpid.bytebuffer.QpidByteBuffer;
 import org.apache.qpid.server.transport.ProtocolEngine;
 import org.apache.qpid.server.consumer.AbstractConsumerTarget;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.plugin.MessageConverter;
@@ -106,7 +106,7 @@
 
     }
 
-    public void doSend(final ConsumerImpl consumer, final MessageInstance entry, boolean batch)
+    public void doSend(final MessageInstanceConsumer consumer, final MessageInstance entry, boolean batch)
     {
         // TODO
         ServerMessage serverMessage = entry.getMessage();
@@ -329,7 +329,7 @@
 
     public void flush()
     {
-        for(ConsumerImpl consumer : getConsumers())
+        for(MessageInstanceConsumer consumer : getConsumers())
         {
             consumer.flush();
         }
@@ -340,16 +340,16 @@
 
         private final MessageInstance _queueEntry;
         private final Binary _deliveryTag;
-        private final ConsumerImpl _consumer;
+        private final MessageInstanceConsumer _consumer;
 
-        public DispositionAction(Binary tag, MessageInstance queueEntry, final ConsumerImpl consumer)
+        public DispositionAction(Binary tag, MessageInstance queueEntry, final MessageInstanceConsumer consumer)
         {
             _deliveryTag = tag;
             _queueEntry = queueEntry;
             _consumer = consumer;
         }
 
-        public ConsumerImpl getConsumer()
+        public MessageInstanceConsumer getConsumer()
         {
             return _consumer;
         }
@@ -522,7 +522,6 @@
         return target instanceof org.apache.qpid.server.protocol.v1_0.type.messaging.Target ? ((org.apache.qpid.server.protocol.v1_0.type.messaging.Target) target).getAddress() : _link.getEndpoint().getName();
     }
 
-    @Override
     public long getUnacknowledgedBytes()
     {
         // TODO
diff --git a/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java b/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
index 40f95da..7145ca9 100644
--- a/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
+++ b/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/SendingLink_1_0.java
@@ -35,6 +35,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.qpid.server.consumer.ConsumerTarget;
+import org.apache.qpid.server.message.ConsumerOption;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.model.NamedAddressSpace;
 import org.apache.qpid.server.protocol.v1_0.type.AmqpErrorException;
 import org.apache.qpid.server.protocol.v1_0.type.Binary;
@@ -61,7 +64,6 @@
 import org.apache.qpid.filter.SelectorParsingException;
 import org.apache.qpid.filter.selector.ParseException;
 import org.apache.qpid.filter.selector.TokenMgrError;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.filter.FilterManager;
 import org.apache.qpid.server.filter.JMSSelectorFilter;
 import org.apache.qpid.server.message.MessageInstance;
@@ -84,7 +86,7 @@
     private NamedAddressSpace _addressSpace;
     private SendingDestination _destination;
 
-    private ConsumerImpl _consumer;
+    private MessageInstanceConsumer _consumer;
     private ConsumerTarget_1_0 _target;
 
     private boolean _draining;
@@ -114,7 +116,7 @@
         linkAttachment.setDeliveryStateHandler(this);
         QueueDestination qd = null;
 
-        EnumSet<ConsumerImpl.Option> options = EnumSet.noneOf(ConsumerImpl.Option.class);
+        EnumSet<ConsumerOption> options = EnumSet.noneOf(ConsumerOption.class);
 
 
         boolean noLocal = false;
@@ -170,8 +172,8 @@
             _target = new ConsumerTarget_1_0(this, source.getDistributionMode() != StdDistMode.COPY);
             if(source.getDistributionMode() != StdDistMode.COPY)
             {
-                options.add(ConsumerImpl.Option.ACQUIRES);
-                options.add(ConsumerImpl.Option.SEES_REQUEUES);
+                options.add(ConsumerOption.ACQUIRES);
+                options.add(ConsumerOption.SEES_REQUEUES);
             }
 
         }
@@ -330,8 +332,8 @@
 
 
             _target = new ConsumerTarget_1_0(this, true);
-            options.add(ConsumerImpl.Option.ACQUIRES);
-            options.add(ConsumerImpl.Option.SEES_REQUEUES);
+            options.add(ConsumerOption.ACQUIRES);
+            options.add(ConsumerOption.SEES_REQUEUES);
 
         }
         else
@@ -343,13 +345,13 @@
         {
             if(noLocal)
             {
-                options.add(ConsumerImpl.Option.NO_LOCAL);
+                options.add(ConsumerOption.NO_LOCAL);
             }
 
             if(_durability == TerminusDurability.CONFIGURATION ||
                _durability == TerminusDurability.UNSETTLED_STATE )
             {
-                options.add(ConsumerImpl.Option.DURABLE);
+                options.add(ConsumerOption.DURABLE);
             }
 
             try
@@ -588,7 +590,7 @@
     public synchronized void setLinkAttachment(SendingLinkAttachment linkAttachment)
     {
 
-        if(_consumer.isActive())
+        if(_target.getState() == ConsumerTarget.State.ACTIVE)
         {
             _target.suspend();
         }
@@ -694,7 +696,7 @@
         return _addressSpace;
     }
 
-    public ConsumerImpl getConsumer()
+    public MessageInstanceConsumer getConsumer()
     {
         return _consumer;
     }
diff --git a/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java b/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
index 744f009..40f22ec 100644
--- a/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
+++ b/broker-plugins/amqp-1-0-protocol/src/main/java/org/apache/qpid/server/protocol/v1_0/Session_1_0.java
@@ -45,7 +45,24 @@
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.bytebuffer.QpidByteBuffer;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.server.connection.SessionPrincipal;
+import org.apache.qpid.server.consumer.ConsumerTarget;
+import org.apache.qpid.server.logging.LogSubject;
+import org.apache.qpid.server.message.MessageDestination;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
+import org.apache.qpid.server.message.MessageSource;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
+import org.apache.qpid.server.model.ConfigurationChangeListener;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Consumer;
+import org.apache.qpid.server.model.Exchange;
 import org.apache.qpid.server.model.NamedAddressSpace;
+import org.apache.qpid.server.model.Queue;
+import org.apache.qpid.server.model.Session;
+import org.apache.qpid.server.protocol.AMQSessionModel;
+import org.apache.qpid.server.protocol.ConsumerListener;
+import org.apache.qpid.server.protocol.LinkRegistry;
 import org.apache.qpid.server.protocol.v1_0.framing.OversizeFrameException;
 import org.apache.qpid.server.protocol.v1_0.type.AmqpErrorException;
 import org.apache.qpid.server.protocol.v1_0.type.Binary;
@@ -75,22 +92,6 @@
 import org.apache.qpid.server.protocol.v1_0.type.transport.LinkError;
 import org.apache.qpid.server.protocol.v1_0.type.transport.Role;
 import org.apache.qpid.server.protocol.v1_0.type.transport.Transfer;
-import org.apache.qpid.protocol.AMQConstant;
-import org.apache.qpid.server.connection.SessionPrincipal;
-import org.apache.qpid.server.consumer.ConsumerImpl;
-import org.apache.qpid.server.consumer.ConsumerTarget;
-import org.apache.qpid.server.logging.LogSubject;
-import org.apache.qpid.server.message.MessageDestination;
-import org.apache.qpid.server.message.MessageSource;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
-import org.apache.qpid.server.model.ConfiguredObject;
-import org.apache.qpid.server.model.Consumer;
-import org.apache.qpid.server.model.Exchange;
-import org.apache.qpid.server.model.Queue;
-import org.apache.qpid.server.model.Session;
-import org.apache.qpid.server.protocol.AMQSessionModel;
-import org.apache.qpid.server.protocol.ConsumerListener;
-import org.apache.qpid.server.protocol.LinkRegistry;
 import org.apache.qpid.server.security.SecurityToken;
 import org.apache.qpid.server.transport.AMQPConnection;
 import org.apache.qpid.server.txn.AutoCommitTransaction;
@@ -1042,7 +1043,7 @@
 
     private void registerConsumer(final SendingLink_1_0 link)
     {
-        ConsumerImpl consumer = link.getConsumer();
+        MessageInstanceConsumer consumer = link.getConsumer();
         if(consumer instanceof Consumer<?>)
         {
             Consumer<?> modelConsumer = (Consumer<?>) consumer;
@@ -1628,7 +1629,7 @@
         }
     }
 
-    private class ConsumerClosedListener implements ConfigurationChangeListener
+    private class ConsumerClosedListener extends AbstractConfigurationChangeListener
     {
         @Override
         public void stateChanged(final ConfiguredObject object, final org.apache.qpid.server.model.State oldState, final org.apache.qpid.server.model.State newState)
@@ -1638,39 +1639,6 @@
                 consumerRemoved((Consumer<?>)object);
             }
         }
-
-        @Override
-        public void childAdded(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void childRemoved(final ConfiguredObject object, final ConfiguredObject child)
-        {
-
-        }
-
-        @Override
-        public void attributeSet(final ConfiguredObject object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-
-        }
     }
 
     @Override
diff --git a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java
index 35ad562..bfac0d6 100644
--- a/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java
+++ b/broker-plugins/logging-logback/src/main/java/org/apache/qpid/server/logging/logback/AbstractLogger.java
@@ -36,9 +36,9 @@
 import org.slf4j.LoggerFactory;
 
 import org.apache.qpid.server.logging.LogInclusionRule;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.AbstractConfiguredObject;
 import org.apache.qpid.server.model.BrokerLogInclusionRule;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ConfiguredObjectTypeRegistry;
 import org.apache.qpid.server.model.ManagedObject;
@@ -149,7 +149,7 @@
         }
     }
 
-    private class LogInclusionRuleListener implements ConfigurationChangeListener
+    private class LogInclusionRuleListener extends AbstractConfigurationChangeListener
     {
 
         @Override
@@ -170,28 +170,6 @@
             }
         }
 
-        @Override
-        public void stateChanged(final ConfiguredObject<?> object, final State oldState, final State newState)
-        {
-        }
-
-        @Override
-        public void attributeSet(final ConfiguredObject<?> object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-        }
     }
 
     public static Map<String, Collection<String>> getSupportedVirtualHostLoggerChildTypes()
diff --git a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementAddressSpace.java b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementAddressSpace.java
index ee633f6..7ee2200 100644
--- a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementAddressSpace.java
+++ b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementAddressSpace.java
@@ -29,9 +29,9 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
-import org.apache.qpid.server.message.MessageInstance;
 import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.model.Broker;
@@ -237,7 +237,7 @@
                                                                                      final String routingAddress,
                                                                                      final InstanceProperties instanceProperties,
                                                                                      final ServerTransaction txn,
-                                                                                     final Action<? super MessageInstance> postEnqueueAction)
+                                                                                     final Action<? super BaseMessageInstance> postEnqueueAction)
         {
             MessageDestination destination = getAttainedMessageDestination(routingAddress);
             if(destination == null || destination == this)
diff --git a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java
index 243da37..b1e2650 100644
--- a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java
+++ b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNode.java
@@ -41,19 +41,22 @@
 import javax.security.auth.Subject;
 
 import org.apache.qpid.server.connection.SessionPrincipal;
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
 import org.apache.qpid.server.filter.FilterManager;
 import org.apache.qpid.server.filter.Filterable;
 import org.apache.qpid.server.message.AMQMessageHeader;
+import org.apache.qpid.server.message.AcquiringMessageInstanceConsumer;
+import org.apache.qpid.server.message.BaseMessageInstance;
+import org.apache.qpid.server.message.ConsumerOption;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.MessageSource;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.message.internal.InternalMessage;
 import org.apache.qpid.server.message.internal.InternalMessageHeader;
-import org.apache.qpid.server.model.ConfigurationChangeListener;
+import org.apache.qpid.server.model.AbstractConfigurationChangeListener;
 import org.apache.qpid.server.model.ConfiguredObject;
 import org.apache.qpid.server.model.ManagedObject;
 import org.apache.qpid.server.model.NamedAddressSpace;
@@ -71,7 +74,7 @@
 import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.util.StateChangeListener;
 
-class ManagementNode implements MessageSource, MessageDestination
+class ManagementNode implements MessageSource<ManagementNodeConsumer>, MessageDestination
 {
 
     public static final String NAME_ATTRIBUTE = "name";
@@ -263,7 +266,7 @@
                                                                                   final String routingAddress,
                                                                                   final InstanceProperties instanceProperties,
                                                                                   final ServerTransaction txn,
-                                                                                  final Action<? super MessageInstance> postEnqueueAction)
+                                                                                  final Action<? super BaseMessageInstance> postEnqueueAction)
     {
 
         @SuppressWarnings("unchecked")
@@ -982,7 +985,7 @@
                                                             final FilterManager filters,
                                                             final Class<? extends ServerMessage> messageClass,
                                                             final String consumerName,
-                                                            final EnumSet<ConsumerImpl.Option> options,
+                                                            final EnumSet<ConsumerOption> options,
                                                             final Integer priority)
     {
 
@@ -1099,7 +1102,7 @@
         }
 
         @Override
-        public ConsumerImpl getAcquiringConsumer()
+        public MessageInstanceConsumer getAcquiringConsumer()
         {
             return null;
         }
@@ -1111,13 +1114,13 @@
         }
 
         @Override
-        public boolean isAcquiredBy(final ConsumerImpl consumer)
+        public boolean isAcquiredBy(final MessageInstanceConsumer consumer)
         {
             return false;
         }
 
         @Override
-        public boolean removeAcquisitionFromConsumer(final ConsumerImpl consumer)
+        public boolean removeAcquisitionFromConsumer(final MessageInstanceConsumer consumer)
         {
             return false;
         }
@@ -1135,7 +1138,7 @@
         }
 
         @Override
-        public ConsumerImpl getDeliveredConsumer()
+        public AcquiringMessageInstanceConsumer<?,?> getDeliveredConsumer()
         {
             return null;
         }
@@ -1147,7 +1150,7 @@
         }
 
         @Override
-        public boolean isRejectedBy(final ConsumerImpl consumer)
+        public boolean isRejectedBy(final MessageInstanceConsumer consumer)
         {
             return false;
         }
@@ -1165,13 +1168,13 @@
         }
 
         @Override
-        public boolean acquire(final ConsumerImpl sub)
+        public boolean acquire(final MessageInstanceConsumer sub)
         {
             return false;
         }
 
         @Override
-        public boolean makeAcquisitionUnstealable(final ConsumerImpl consumer)
+        public boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer)
         {
             return false;
         }
@@ -1189,7 +1192,7 @@
         }
 
         @Override
-        public int routeToAlternate(final Action<? super MessageInstance> action,
+        public int routeToAlternate(final Action<? super BaseMessageInstance> action,
                                     final ServerTransaction txn)
         {
             return 0;
@@ -1227,7 +1230,7 @@
         }
 
         @Override
-        public void release(final ConsumerImpl release)
+        public void release(final MessageInstanceConsumer release)
         {
 
         }
@@ -1275,7 +1278,7 @@
         }
     }
 
-    private class ModelObjectListener implements ConfigurationChangeListener
+    private class ModelObjectListener extends AbstractConfigurationChangeListener
     {
         @Override
         public void stateChanged(final ConfiguredObject object, final State oldState, final State newState)
@@ -1328,27 +1331,6 @@
                 _entities.get(entityType).remove(child.getName());
             }
         }
-
-        @Override
-        public void attributeSet(final ConfiguredObject object,
-                                 final String attributeName,
-                                 final Object oldAttributeValue,
-                                 final Object newAttributeValue)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeStart(final ConfiguredObject<?> object)
-        {
-
-        }
-
-        @Override
-        public void bulkChangeEnd(final ConfiguredObject<?> object)
-        {
-
-        }
     }
 
     private static class MutableMessageHeader implements AMQMessageHeader
diff --git a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java
index 9890992..e46273d 100644
--- a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java
+++ b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementNodeConsumer.java
@@ -26,12 +26,11 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.consumer.ConsumerTarget;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageDestination;
-import org.apache.qpid.server.message.MessageInstance;
-import org.apache.qpid.server.message.MessageSource;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.message.internal.InternalMessage;
 import org.apache.qpid.server.model.NamedAddressSpace;
@@ -42,15 +41,14 @@
 import org.apache.qpid.server.util.Action;
 import org.apache.qpid.server.util.StateChangeListener;
 
-class ManagementNodeConsumer implements ConsumerImpl, MessageDestination
+class ManagementNodeConsumer implements MessageInstanceConsumer, MessageDestination
 {
-    private final long _id = ConsumerImpl.CONSUMER_NUMBER_GENERATOR.getAndIncrement();
     private final ManagementNode _managementNode;
     private final List<ManagementResponse> _queue = Collections.synchronizedList(new ArrayList<ManagementResponse>());
     private final ConsumerTarget _target;
     private final String _name;
     private final StateChangeListener<ConsumerTarget, ConsumerTarget.State> _targetChangeListener = new TargetChangeListener();
-
+    private final Object _identifier = new Object();
 
     public ManagementNodeConsumer(final String consumerName, final ManagementNode managementNode, ConsumerTarget target)
     {
@@ -67,6 +65,11 @@
     }
 
     @Override
+    public Object getIdentifier()
+    {
+        return _identifier;
+    }
+
     public boolean hasAvailableMessages()
     {
         return !_queue.isEmpty();
@@ -78,53 +81,12 @@
 
     }
 
-    @Override
-    public long getBytesOut()
-    {
-        return 0;
-    }
 
-    @Override
-    public long getMessagesOut()
-    {
-        return 0;
-    }
-
-    @Override
-    public long getUnacknowledgedBytes()
-    {
-        return 0;
-    }
-
-    @Override
-    public long getUnacknowledgedMessages()
-    {
-        return 0;
-    }
-
-    @Override
     public AMQSessionModel getSessionModel()
     {
         return _target.getSessionModel();
     }
 
-    @Override
-    public MessageSource getMessageSource()
-    {
-        return _managementNode;
-    }
-
-    @Override
-    public long getConsumerNumber()
-    {
-        return _id;
-    }
-
-    @Override
-    public boolean isSuspended()
-    {
-        return false;
-    }
 
     @Override
     public boolean isClosed()
@@ -139,42 +101,11 @@
     }
 
     @Override
-    public boolean seesRequeues()
-    {
-        return false;
-    }
-
-    @Override
     public void close()
     {
     }
 
     @Override
-    public boolean trySendLock()
-    {
-        return _target.trySendLock();
-    }
-
-    @Override
-    public void getSendLock()
-    {
-        _target.getSendLock();
-    }
-
-    @Override
-    public void releaseSendLock()
-    {
-        _target.releaseSendLock();
-    }
-
-
-    @Override
-    public boolean isActive()
-    {
-        return false;
-    }
-
-    @Override
     public NamedAddressSpace getAddressSpace()
     {
         return _managementNode.getAddressSpace();
@@ -198,7 +129,7 @@
                                                                                  final String routingAddress,
                                                                                  final InstanceProperties instanceProperties,
                                                                                  final ServerTransaction txn,
-                                                                                 final Action<? super MessageInstance> postEnqueueAction)
+                                                                                 final Action<? super BaseMessageInstance> postEnqueueAction)
     {
         send((InternalMessage)message);
         return 1;
@@ -210,7 +141,6 @@
 
     }
 
-    @Override
     public ConsumerTarget getTarget()
     {
         return _target;
diff --git a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java
index 0b17b0f..71d0225 100644
--- a/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java
+++ b/broker-plugins/management-amqp/src/main/java/org/apache/qpid/server/management/amqp/ManagementResponse.java
@@ -20,10 +20,11 @@
  */
 package org.apache.qpid.server.management.amqp;
 
-import org.apache.qpid.server.consumer.ConsumerImpl;
 import org.apache.qpid.server.filter.Filterable;
+import org.apache.qpid.server.message.BaseMessageInstance;
 import org.apache.qpid.server.message.InstanceProperties;
 import org.apache.qpid.server.message.MessageInstance;
+import org.apache.qpid.server.message.MessageInstanceConsumer;
 import org.apache.qpid.server.message.ServerMessage;
 import org.apache.qpid.server.message.internal.InternalMessage;
 import org.apache.qpid.server.store.MessageEnqueueRecord;
@@ -85,7 +86,7 @@
     }
 
     @Override
-    public ConsumerImpl getAcquiringConsumer()
+    public MessageInstanceConsumer getAcquiringConsumer()
     {
         return _consumer;
     }
@@ -97,13 +98,13 @@
     }
 
     @Override
-    public boolean isAcquiredBy(final ConsumerImpl consumer)
+    public boolean isAcquiredBy(final MessageInstanceConsumer consumer)
     {
         return consumer == _consumer && !isDeleted();
     }
 
     @Override
-    public boolean removeAcquisitionFromConsumer(final ConsumerImpl consumer)
+    public boolean removeAcquisitionFromConsumer(final MessageInstanceConsumer consumer)
     {
         return consumer == _consumer;
     }
@@ -133,7 +134,7 @@
     }
 
     @Override
-    public boolean isRejectedBy(final ConsumerImpl consumer)
+    public boolean isRejectedBy(final MessageInstanceConsumer consumer)
     {
         return false;
     }
@@ -151,13 +152,13 @@
     }
 
     @Override
-    public boolean acquire(final ConsumerImpl sub)
+    public boolean acquire(final MessageInstanceConsumer sub)
     {
         return false;
     }
 
     @Override
-    public boolean makeAcquisitionUnstealable(final ConsumerImpl consumer)
+    public boolean makeAcquisitionUnstealable(final MessageInstanceConsumer consumer)
     {
         return false;
     }
@@ -175,7 +176,7 @@
     }
 
     @Override
-    public int routeToAlternate(final Action<? super MessageInstance> action,
+    public int routeToAlternate(final Action<? super BaseMessageInstance> action,
                                 final ServerTransaction txn)
     {
         return 0;
@@ -213,7 +214,7 @@
     }
 
     @Override
-    public void release(final ConsumerImpl release)
+    public void release(final MessageInstanceConsumer release)
     {
         release();
     }
diff --git a/client/src/main/java/org/apache/qpid/client/url/URLParser.java b/client/src/main/java/org/apache/qpid/client/url/URLParser.java
index 7791f32..2fe7216 100644
--- a/client/src/main/java/org/apache/qpid/client/url/URLParser.java
+++ b/client/src/main/java/org/apache/qpid/client/url/URLParser.java
@@ -21,16 +21,19 @@
 package org.apache.qpid.client.url;
 
 
-import org.apache.qpid.client.BrokerDetails;
-import org.apache.qpid.client.AMQConnectionFactory;
-import org.apache.qpid.client.AMQConnectionURL;
-import org.apache.qpid.url.URLHelper;
-import org.apache.qpid.url.URLSyntaxException;
-
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.StringTokenizer;
 
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQConnectionURL;
+import org.apache.qpid.client.BrokerDetails;
+import org.apache.qpid.url.URLHelper;
+import org.apache.qpid.url.URLSyntaxException;
+
 public class URLParser
 {
     private AMQConnectionURL _url;
@@ -82,12 +85,12 @@
                 _url.setClientName(connection.getHost());
             }
             
-            String userInfo = connection.getUserInfo();
+            String userInfo = connection.getRawUserInfo();
 
             if (userInfo == null)
             {
-                // Fix for Java 1.5 which doesn't parse UserInfo for non http URIs
-                userInfo = connection.getAuthority();
+                // Fix for Java Environments which don't parse UserInfo for non http URIs
+                userInfo = connection.getRawAuthority();
 
                 if (userInfo != null)
                 {
@@ -178,8 +181,16 @@
         }
         else
         {
-            _url.setUsername(userinfo.substring(0, colonIndex));
-            _url.setPassword(userinfo.substring(colonIndex + 1));
+            try
+            {
+                _url.setUsername(URLDecoder.decode(userinfo.substring(0, colonIndex), StandardCharsets.UTF_8.name()));
+                _url.setPassword(URLDecoder.decode(userinfo.substring(colonIndex + 1), StandardCharsets.UTF_8.name()));
+            }
+            catch (UnsupportedEncodingException e)
+            {
+                throw URLHelper.parseError(AMQConnectionURL.AMQ_PROTOCOL.length() + 3, userinfo.length(),
+                                           e.getLocalizedMessage(), _url.getURL());
+            }
         }
 
     }
diff --git a/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java b/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
index c31eb4d..8bafa85 100644
--- a/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
+++ b/client/src/test/java/org/apache/qpid/test/unit/client/connectionurl/ConnectionURLTest.java
@@ -34,6 +34,26 @@
 
 public class ConnectionURLTest extends QpidTestCase
 {
+
+    public void testPasswordWithColon() throws URLSyntaxException
+    {
+        String url = "amqp://PQ-RST-UV-W:VPN%3amwrst@/test?brokerlist='tcp://localhost:5672'";
+        ConnectionURL connectionurl = new AMQConnectionURL(url);
+        assertEquals("PQ-RST-UV-W", connectionurl.getUsername());
+        assertEquals("VPN:mwrst", connectionurl.getPassword());
+        assertEquals("/test",connectionurl.getVirtualHost());
+    }
+
+    public void testUsernameWithColon() throws URLSyntaxException
+    {
+        String url = "amqp://PQ%3aRST-UV-W:VPN%3amwrst@/test?brokerlist='tcp://localhost:5672'";
+        ConnectionURL connectionurl = new AMQConnectionURL(url);
+        assertEquals("PQ:RST-UV-W", connectionurl.getUsername());
+        assertEquals("VPN:mwrst", connectionurl.getPassword());
+        assertEquals("/test",connectionurl.getVirtualHost());
+    }
+
+
     public void testFailoverURL() throws URLSyntaxException
     {
         String url = "amqp://ritchiem:bob@/test?brokerlist='tcp://localhost:5672;tcp://fancyserver:3000/',failover='roundrobin?cyclecount='100''";
diff --git a/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index a15ef99..ff3cf90 100644
--- a/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -414,6 +414,28 @@
         }
     }
 
+    public FieldArray getFieldArray(String string)
+    {
+        return getFieldArray(AMQShortString.valueOf(string));
+    }
+
+    public FieldArray getFieldArray(AMQShortString string)
+    {
+        AMQTypedValue value = getProperty(string);
+
+        if ((value != null) && (value.getType() == AMQType.FIELD_ARRAY))
+        {
+            return (FieldArray) value.getValue();
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+
+
+
     public Object getObject(String string)
     {
         return getObject(AMQShortString.valueOf(string));
diff --git a/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java b/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
index cb985f5..cfefe59 100644
--- a/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
+++ b/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
@@ -95,4 +95,10 @@
         }
         processor.receiveHeartbeat();
     }
+
+    @Override
+    public String toString()
+    {
+        return "[HeartbeatBody]";
+    }
 }