You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2014/09/23 20:20:25 UTC

[01/27] Initial drop of donated AMQP Client Code.

Repository: qpid-jms
Updated Branches:
  refs/heads/master 99f60c210 -> e4decdc1e


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/QpidJmsTestSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/QpidJmsTestSupport.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/QpidJmsTestSupport.java
new file mode 100644
index 0000000..abb1bb4
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/QpidJmsTestSupport.java
@@ -0,0 +1,447 @@
+/**
+ * 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.jms.support;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.apache.activemq.ActiveMQConnectionFactory;
+import org.apache.activemq.broker.BrokerPlugin;
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.activemq.broker.jmx.BrokerViewMBean;
+import org.apache.activemq.broker.jmx.ConnectorViewMBean;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.broker.jmx.TopicViewMBean;
+import org.apache.activemq.filter.DestinationMapEntry;
+import org.apache.activemq.security.AuthenticationUser;
+import org.apache.activemq.security.AuthorizationEntry;
+import org.apache.activemq.security.AuthorizationPlugin;
+import org.apache.activemq.security.DefaultAuthorizationMap;
+import org.apache.activemq.security.SimpleAuthenticationPlugin;
+import org.apache.activemq.security.TempDestinationAuthorizationEntry;
+import org.apache.activemq.store.kahadb.KahaDBStore;
+import org.apache.activemq.util.JMXSupport;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for all protocol test support classes.
+ */
+public class QpidJmsTestSupport {
+
+    public static final String KAHADB_DIRECTORY = "target/activemq-data";
+
+    @Rule public TestName name = new TestName();
+
+    protected static final Logger LOG = LoggerFactory.getLogger(QpidJmsTestSupport.class);
+    protected BrokerService brokerService;
+    protected final List<BrokerService> brokers = new ArrayList<BrokerService>();
+    protected final Vector<Throwable> exceptions = new Vector<Throwable>();
+    protected int numberOfMessages;
+    protected Connection connection;
+
+    @Before
+    public void setUp() throws Exception {
+        exceptions.clear();
+        startPrimaryBroker();
+        this.numberOfMessages = 2000;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (connection != null) {
+            connection.close();
+        }
+        stopPrimaryBroker();
+        for (BrokerService broker : brokers) {
+            try {
+                stopBroker(broker);
+            } catch (Exception ex) {}
+        }
+    }
+
+    public String getDestinationName() {
+        return name.getMethodName();
+    }
+
+    public URI getBrokerActiveMQClientConnectionURI() {
+        try {
+            return new URI("tcp://127.0.0.1:" +
+                brokerService.getTransportConnectorByName("openwire").getPublishableConnectURI().getPort());
+        } catch (Exception e) {
+            throw new RuntimeException();
+        }
+    }
+
+    protected boolean isPersistent() {
+        return false;
+    }
+
+    protected boolean isAdvisorySupport() {
+        return false;
+    }
+
+    protected BrokerService createBroker(String name, boolean deleteAllMessages) throws Exception {
+        return createBroker(name, deleteAllMessages, Collections.<String, Integer> emptyMap());
+    }
+
+    protected void configureBrokerPolicies(BrokerService broker) {
+
+    }
+
+    protected BrokerService createBroker(String name, boolean deleteAllMessages, Map<String, Integer> portMap) throws Exception {
+        KahaDBStore kaha = new KahaDBStore();
+        kaha.setDirectory(new File(KAHADB_DIRECTORY + "/" + name));
+
+        BrokerService brokerService = new BrokerService();
+        brokerService.setBrokerName(name);
+        brokerService.setPersistent(isPersistent());
+        brokerService.setAdvisorySupport(isAdvisorySupport());
+        brokerService.setDeleteAllMessagesOnStartup(deleteAllMessages);
+        brokerService.setUseJmx(true);
+        brokerService.setDataDirectory("target/" + name);
+        brokerService.setPersistenceAdapter(kaha);
+        brokerService.setStoreOpenWireVersion(10);
+
+        configureBrokerPolicies(brokerService);
+
+        ArrayList<BrokerPlugin> plugins = new ArrayList<BrokerPlugin>();
+        BrokerPlugin authenticationPlugin = configureAuthentication();
+        if (authenticationPlugin != null) {
+            plugins.add(configureAuthorization());
+        }
+
+        BrokerPlugin authorizationPlugin = configureAuthorization();
+        if (authorizationPlugin != null) {
+            plugins.add(configureAuthentication());
+        }
+
+        if (!plugins.isEmpty()) {
+            BrokerPlugin[] array = new BrokerPlugin[plugins.size()];
+            brokerService.setPlugins(plugins.toArray(array));
+        }
+
+        addOpenWireConnector(brokerService, portMap);
+        addAdditionalConnectors(brokerService, portMap);
+
+        return brokerService;
+    }
+
+    protected int addOpenWireConnector(BrokerService brokerService, Map<String, Integer> portMap) throws Exception {
+        int port = 0;
+        if (portMap.containsKey("openwire")) {
+            port = portMap.get("openwire");
+        }
+        TransportConnector connector = brokerService.addConnector("tcp://0.0.0.0:" + port + "?trace=true");
+        connector.setName("openwire");
+        int openwirePort = connector.getPublishableConnectURI().getPort();
+        LOG.debug("Using openwire port: {}", openwirePort);
+        return openwirePort;
+    }
+
+    protected void addAdditionalConnectors(BrokerService brokerService, Map<String, Integer> portMap) throws Exception {
+        // Subclasses can add their own connectors, we don't add any here.
+    }
+
+    public void startPrimaryBroker() throws Exception {
+        if (brokerService != null && brokerService.isStarted()) {
+            throw new IllegalStateException("Broker is already created.");
+        }
+
+        brokerService = createBroker("localhost", true);
+        brokerService.start();
+        brokerService.waitUntilStarted();
+    }
+
+    public void restartPrimaryBroker() throws Exception {
+        stopBroker(brokerService);
+        brokerService = restartBroker(brokerService);
+    }
+
+    public void stopPrimaryBroker() throws Exception {
+        stopBroker(brokerService);
+    }
+
+    public void startNewBroker() throws Exception {
+        String brokerName = "localhost" + (brokers.size() + 1);
+
+        BrokerService brokerService = createBroker(brokerName, true);
+        brokerService.setUseJmx(false);
+        brokerService.start();
+        brokerService.waitUntilStarted();
+
+        brokers.add(brokerService);
+    }
+
+    public BrokerService restartBroker(BrokerService brokerService) throws Exception {
+        String name = brokerService.getBrokerName();
+        Map<String, Integer> portMap = new HashMap<String, Integer>();
+        for (TransportConnector connector : brokerService.getTransportConnectors()) {
+            portMap.put(connector.getName(), connector.getPublishableConnectURI().getPort());
+        }
+
+        stopBroker(brokerService);
+        BrokerService broker = createBroker(name, false, portMap);
+        broker.start();
+        broker.waitUntilStarted();
+        return broker;
+    }
+
+    public void stopBroker(BrokerService broker) throws Exception {
+        if (broker != null) {
+            broker.stop();
+            broker.waitUntilStopped();
+        }
+    }
+
+    public List<URI> getBrokerURIs() throws Exception {
+        ArrayList<URI> result = new ArrayList<URI>();
+        result.add(brokerService.getTransportConnectorByName("amqp").getPublishableConnectURI());
+
+        for (BrokerService broker : brokers) {
+            result.add(broker.getTransportConnectorByName("amqp").getPublishableConnectURI());
+        }
+
+        return result;
+    }
+
+    public Connection createActiveMQConnection() throws Exception {
+        return createActiveMQConnection(getBrokerActiveMQClientConnectionURI());
+    }
+
+    public Connection createActiveMQConnection(URI brokerURI) throws Exception {
+        ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURI);
+        return factory.createConnection();
+    }
+
+    public void sendMessages(Connection connection, Destination destination, int count) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageProducer p = session.createProducer(destination);
+
+        for (int i = 0; i < count; i++) {
+            TextMessage message = session.createTextMessage();
+            message.setText("TextMessage: " + i);
+            p.send(message);
+        }
+
+        session.close();
+    }
+
+    protected BrokerViewMBean getProxyToBroker() throws MalformedObjectNameException, JMSException {
+        return getProxyToBroker(brokerService);
+    }
+
+    protected BrokerViewMBean getProxyToBroker(BrokerService broker) throws MalformedObjectNameException, JMSException {
+        ObjectName brokerViewMBean = broker.getBrokerObjectName();
+        BrokerViewMBean proxy = (BrokerViewMBean) brokerService.getManagementContext()
+                .newProxyInstance(brokerViewMBean, BrokerViewMBean.class, true);
+        return proxy;
+    }
+
+    protected ConnectorViewMBean getProxyToConnectionView(String connectionType) throws Exception {
+        return getProxyToConnectionView(connectionType);
+    }
+
+    protected ConnectorViewMBean getProxyToConnectionView(BrokerService broker, String connectionType) throws Exception {
+        ObjectName connectorQuery = new ObjectName(
+            broker.getBrokerObjectName() + ",connector=clientConnectors,connectorName="+connectionType+"_//*");
+
+        Set<ObjectName> results = brokerService.getManagementContext().queryNames(connectorQuery, null);
+        if (results == null || results.isEmpty() || results.size() > 1) {
+            throw new Exception("Unable to find the exact Connector instance.");
+        }
+
+        ConnectorViewMBean proxy = (ConnectorViewMBean) brokerService.getManagementContext()
+                .newProxyInstance(results.iterator().next(), ConnectorViewMBean.class, true);
+        return proxy;
+    }
+
+    protected QueueViewMBean getProxyToQueue(String name) throws MalformedObjectNameException, JMSException {
+        return getProxyToQueue(brokerService, name);
+    }
+
+    protected QueueViewMBean getProxyToQueue(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
+        ObjectName queueViewMBeanName = new ObjectName(
+            broker.getBrokerObjectName() + ",destinationType=Queue,destinationName=" + name);
+        QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext()
+                .newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true);
+        return proxy;
+    }
+
+    protected QueueViewMBean getProxyToTemporaryQueue(String name) throws MalformedObjectNameException, JMSException {
+        return getProxyToTemporaryQueue(brokerService, name);
+    }
+
+    protected QueueViewMBean getProxyToTemporaryQueue(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
+        name = JMXSupport.encodeObjectNamePart(name);
+        ObjectName queueViewMBeanName = new ObjectName(
+            broker.getBrokerObjectName() + ",destinationType=TempQueue,destinationName=" + name);
+        QueueViewMBean proxy = (QueueViewMBean) brokerService.getManagementContext()
+                .newProxyInstance(queueViewMBeanName, QueueViewMBean.class, true);
+        return proxy;
+    }
+
+    protected TopicViewMBean getProxyToTopic(String name) throws MalformedObjectNameException, JMSException {
+        return getProxyToTopic(brokerService, name);
+    }
+
+    protected TopicViewMBean getProxyToTopic(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
+        ObjectName topicViewMBeanName = new ObjectName(
+            broker.getBrokerObjectName() + ",destinationType=Topic,destinationName=" + name);
+        TopicViewMBean proxy = (TopicViewMBean) brokerService.getManagementContext()
+                .newProxyInstance(topicViewMBeanName, TopicViewMBean.class, true);
+        return proxy;
+    }
+
+    protected TopicViewMBean getProxyToTemporaryTopic(String name) throws MalformedObjectNameException, JMSException {
+        return getProxyToTemporaryTopic(brokerService, name);
+    }
+
+    protected TopicViewMBean getProxyToTemporaryTopic(BrokerService broker, String name) throws MalformedObjectNameException, JMSException {
+        name = JMXSupport.encodeObjectNamePart(name);
+        ObjectName topicViewMBeanName = new ObjectName(
+            broker.getBrokerObjectName() + ",destinationType=TempTopic,destinationName=" + name);
+        TopicViewMBean proxy = (TopicViewMBean) brokerService.getManagementContext()
+            .newProxyInstance(topicViewMBeanName, TopicViewMBean.class, true);
+        return proxy;
+    }
+
+    protected void sendToAmqQueue(int count) throws Exception {
+        Connection activemqConnection = createActiveMQConnection();
+        Session amqSession = activemqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue amqTestQueue = amqSession.createQueue(name.getMethodName());
+        sendMessages(activemqConnection, amqTestQueue, count);
+    }
+
+    protected void sendToAmqTopic(int count) throws Exception {
+        Connection activemqConnection = createActiveMQConnection();
+        Session amqSession = activemqConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Topic amqTestTopic = amqSession.createTopic(name.getMethodName());
+        sendMessages(activemqConnection, amqTestTopic, count);
+    }
+
+    protected BrokerPlugin configureAuthentication() throws Exception {
+        List<AuthenticationUser> users = new ArrayList<AuthenticationUser>();
+        users.add(new AuthenticationUser("system", "manager", "users,admins"));
+        users.add(new AuthenticationUser("user", "password", "users"));
+        users.add(new AuthenticationUser("guest", "password", "guests"));
+        SimpleAuthenticationPlugin authenticationPlugin = new SimpleAuthenticationPlugin(users);
+        authenticationPlugin.setAnonymousAccessAllowed(true);
+
+        return authenticationPlugin;
+    }
+
+    protected BrokerPlugin configureAuthorization() throws Exception {
+
+        @SuppressWarnings("rawtypes")
+        List<DestinationMapEntry> authorizationEntries = new ArrayList<DestinationMapEntry>();
+
+        AuthorizationEntry entry = new AuthorizationEntry();
+        entry.setQueue(">");
+        entry.setRead("admins,anonymous");
+        entry.setWrite("admins,anonymous");
+        entry.setAdmin("admins,anonymous");
+        authorizationEntries.add(entry);
+        entry = new AuthorizationEntry();
+        entry.setQueue("USERS.>");
+        entry.setRead("users,anonymous");
+        entry.setWrite("users,anonymous");
+        entry.setAdmin("users,anonymous");
+        authorizationEntries.add(entry);
+        entry = new AuthorizationEntry();
+        entry.setQueue("GUEST.>");
+        entry.setRead("guests,anonymous");
+        entry.setWrite("guests,users,anonymous");
+        entry.setAdmin("guests,users,anonymous");
+        authorizationEntries.add(entry);
+        entry = new AuthorizationEntry();
+        entry.setTopic(">");
+        entry.setRead("admins,anonymous");
+        entry.setWrite("admins,anonymous");
+        entry.setAdmin("admins,anonymous");
+        authorizationEntries.add(entry);
+        entry = new AuthorizationEntry();
+        entry.setTopic("USERS.>");
+        entry.setRead("users,anonymous");
+        entry.setWrite("users,anonymous");
+        entry.setAdmin("users,anonymous");
+        authorizationEntries.add(entry);
+        entry = new AuthorizationEntry();
+        entry.setTopic("GUEST.>");
+        entry.setRead("guests,anonymous");
+        entry.setWrite("guests,users,anonymous");
+        entry.setAdmin("guests,users,anonymous");
+        authorizationEntries.add(entry);
+        entry = new AuthorizationEntry();
+        entry.setTopic("ActiveMQ.Advisory.>");
+        entry.setRead("guests,users,anonymous");
+        entry.setWrite("guests,users,anonymous");
+        entry.setAdmin("guests,users,anonymous");
+        authorizationEntries.add(entry);
+
+        TempDestinationAuthorizationEntry tempEntry = new TempDestinationAuthorizationEntry();
+        tempEntry.setRead("admins,anonymous");
+        tempEntry.setWrite("admins,anonymous");
+        tempEntry.setAdmin("admins,anonymous");
+
+        DefaultAuthorizationMap authorizationMap = new DefaultAuthorizationMap(authorizationEntries);
+        authorizationMap.setTempDestinationAuthorizationEntry(tempEntry);
+        AuthorizationPlugin authorizationPlugin = new AuthorizationPlugin(authorizationMap);
+
+        return authorizationPlugin;
+    }
+
+    protected boolean isForceAsyncSends() {
+        return false;
+    }
+
+    protected boolean isAlwaysSyncSend() {
+        return false;
+    }
+
+    protected boolean isMessagePrioritySupported() {
+        return true;
+    }
+
+    protected boolean isSendAcksAsync() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/Wait.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/Wait.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/Wait.java
new file mode 100644
index 0000000..10f511e
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/Wait.java
@@ -0,0 +1,48 @@
+/**
+ * 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.jms.support;
+
+import java.util.concurrent.TimeUnit;
+
+public class Wait {
+
+    public static final long MAX_WAIT_MILLIS = 30 * 1000;
+    public static final int SLEEP_MILLIS = 1000;
+
+    public interface Condition {
+        boolean isSatisified() throws Exception;
+    }
+
+    public static boolean waitFor(Condition condition) throws Exception {
+        return waitFor(condition, MAX_WAIT_MILLIS);
+    }
+
+    public static boolean waitFor(final Condition condition, final long duration) throws Exception {
+        return waitFor(condition, duration, SLEEP_MILLIS);
+    }
+
+    public static boolean waitFor(final Condition condition, final long duration, final int sleepMillis) throws Exception {
+
+        final long expiry = System.currentTimeMillis() + duration;
+        boolean conditionSatisified = condition.isSatisified();
+        while (!conditionSatisified && System.currentTimeMillis() < expiry) {
+            TimeUnit.MILLISECONDS.sleep(sleepMillis);
+            conditionSatisified = condition.isSatisified();
+        }
+        return conditionSatisified;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedConsumerTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedConsumerTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedConsumerTest.java
new file mode 100644
index 0000000..49121ad
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedConsumerTest.java
@@ -0,0 +1,208 @@
+/**
+ * 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.jms.transactions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test consumer behavior for Transacted Session Consumers.
+ */
+public class JmsTransactedConsumerTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateConsumerFromTxSession() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        assertNotNull(session);
+        assertTrue(session.getTransacted());
+
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        assertNotNull(consumer);
+    }
+
+    @Test(timeout = 60000)
+    public void testConsumedInTxAreAcked() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        sendToAmqQueue(1);
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        Message message = consumer.receive(5000);
+        assertNotNull(message);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        session.commit();
+
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testReceiveAndRollback() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        sendToAmqQueue(2);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(2, proxy.getQueueSize());
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        Message message = consumer.receive(1000);
+        assertNotNull(message);
+        session.commit();
+
+        assertEquals(1, proxy.getQueueSize());
+
+        // rollback so we can get that last message again.
+        message = consumer.receive(1000);
+        assertNotNull(message);
+        session.rollback();
+
+        assertEquals(1, proxy.getQueueSize());
+
+        // Consume again.. the prev message should get redelivered.
+        message = consumer.receive(5000);
+        assertNotNull("Should have re-received the message again!", message);
+        session.commit();
+
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testReceiveTwoThenRollback() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        sendToAmqQueue(2);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(2, proxy.getQueueSize());
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        Message message = consumer.receive(1000);
+        assertNotNull(message);
+        message = consumer.receive(1000);
+        assertNotNull(message);
+        session.rollback();
+
+        assertEquals(2, proxy.getQueueSize());
+
+        // Consume again.. the prev message should get redelivered.
+        message = consumer.receive(5000);
+        assertNotNull("Should have re-received the message again!", message);
+        message = consumer.receive(5000);
+        assertNotNull("Should have re-received the message again!", message);
+        session.commit();
+
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testCloseConsumerBeforeCommit() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        sendToAmqQueue(2);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(2, proxy.getQueueSize());
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        TextMessage message = (TextMessage) consumer.receive(5000);
+        assertNotNull(message);
+        consumer.close();
+
+        assertEquals(2, proxy.getQueueSize());
+        session.commit();
+        assertEquals(1, proxy.getQueueSize());
+
+        // Create a new consumer
+        consumer = session.createConsumer(queue);
+        message = (TextMessage) consumer.receive(1000);
+        session.commit();
+
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @Test(timeout=60000)
+    public void testJMSXDeliveryCount() throws Exception {
+        sendToAmqQueue(1);
+
+        connection = createAmqpConnection();
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        assertEquals(true, session.getTransacted());
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        connection.start();
+
+        // we receive a message...it should be delivered once and not be Re-delivered.
+        Message message = consumer.receive(5000);
+        assertNotNull(message);
+        assertEquals(false, message.getJMSRedelivered());
+        int jmsxDeliveryCount = message.getIntProperty("JMSXDeliveryCount");
+        LOG.info("Incoming message has delivery count: {}", jmsxDeliveryCount);
+        assertEquals(1, jmsxDeliveryCount);
+        session.rollback();
+
+        // we receive again a message
+        message = consumer.receive(5000);
+        assertNotNull(message);
+        assertEquals(true, message.getJMSRedelivered());
+        jmsxDeliveryCount = message.getIntProperty("JMSXDeliveryCount");
+        LOG.info("Redelivered message has delivery count: {}", jmsxDeliveryCount);
+        assertEquals(2, jmsxDeliveryCount);
+        session.rollback();
+
+        // we receive again a message
+        message = consumer.receive(5000);
+        assertNotNull(message);
+        assertEquals(true, message.getJMSRedelivered());
+        jmsxDeliveryCount = message.getIntProperty("JMSXDeliveryCount");
+        LOG.info("Redelivered message has delivery count: {}", jmsxDeliveryCount);
+        assertEquals(3, jmsxDeliveryCount);
+        session.commit();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedProducerTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedProducerTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedProducerTest.java
new file mode 100644
index 0000000..e7f0361
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedProducerTest.java
@@ -0,0 +1,94 @@
+/**
+ * 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.jms.transactions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test for messages produced inside a local transaction.
+ */
+public class JmsTransactedProducerTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateTxSessionAndProducer() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        assertNotNull(session);
+        assertTrue(session.getTransacted());
+
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        assertNotNull(producer);
+    }
+
+    @Test(timeout = 60000)
+    public void testTXProducerCommitsAreQueued() throws Exception {
+        final int MSG_COUNT = 10;
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Session nonTxSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = nonTxSession.createConsumer(queue);
+        MessageProducer producer = session.createProducer(queue);
+
+        for (int i = 0; i < MSG_COUNT; ++i) {
+            producer.send(session.createTextMessage());
+        }
+
+        Message msg = consumer.receive(2000);
+        assertNull(msg);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        session.commit();
+        assertEquals(MSG_COUNT, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testTXProducerRollbacksNotQueued() throws Exception {
+        final int MSG_COUNT = 10;
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+
+        for (int i = 0; i < MSG_COUNT; ++i) {
+            producer.send(session.createTextMessage());
+        }
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        session.rollback();
+        assertEquals(0, proxy.getQueueSize());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedSessionTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedSessionTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedSessionTest.java
new file mode 100644
index 0000000..3dd0647
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/transactions/JmsTransactedSessionTest.java
@@ -0,0 +1,98 @@
+/**
+ * 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.jms.transactions;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Basic tests for Session in Transacted mode.
+ */
+public class JmsTransactedSessionTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateTxSession() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        assertNotNull(session);
+        assertTrue(session.getTransacted());
+
+        session.close();
+    }
+
+    @Test(timeout = 60000)
+    public void testCommitOnSessionWithNoWork() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        assertNotNull(session);
+        assertTrue(session.getTransacted());
+
+        session.commit();
+    }
+
+    @Test(timeout = 60000)
+    public void testRollbackOnSessionWithNoWork() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        assertNotNull(session);
+        assertTrue(session.getTransacted());
+
+        session.rollback();
+    }
+
+    @Test(timeout=60000)
+    public void testCloseSessionRollsBack() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        sendToAmqQueue(2);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(2, proxy.getQueueSize());
+
+        Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message message = consumer.receive(5000);
+        assertNotNull(message);
+        message = consumer.receive(5000);
+        assertNotNull(message);
+
+        assertEquals(2, proxy.getQueueSize());
+        session.close();
+        assertEquals(2, proxy.getQueueSize());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/usecases/JmsLargeMessageSendRecvTimedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/usecases/JmsLargeMessageSendRecvTimedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/usecases/JmsLargeMessageSendRecvTimedTest.java
new file mode 100644
index 0000000..00a1388
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/usecases/JmsLargeMessageSendRecvTimedTest.java
@@ -0,0 +1,114 @@
+/**
+ * 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.jms.usecases;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Random;
+
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JmsLargeMessageSendRecvTimedTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsLargeMessageSendRecvTimedTest.class);
+
+    private final Random rand = new Random(System.currentTimeMillis());
+
+    private byte[] createLargePayload(int sizeInBytes) {
+        byte[] payload = new byte[sizeInBytes];
+        for (int i = 0; i < sizeInBytes; i++) {
+            payload[i] = (byte) rand.nextInt(256);
+        }
+
+        LOG.debug("Created buffer with size : " + sizeInBytes + " bytes");
+        return payload;
+    }
+
+    @Test(timeout = 2 * 60 * 1000)
+    public void testSendSmallerMessages() throws Exception {
+        for (int i = 512; i <= (16 * 1024); i += 512) {
+            doTestSendLargeMessage(i);
+        }
+    }
+
+    @Test(timeout = 2 * 60 * 1000)
+    public void testSendFixedSizedMessages() throws Exception {
+        doTestSendLargeMessage(65536);
+        doTestSendLargeMessage(65536 * 2);
+        doTestSendLargeMessage(65536 * 4);
+    }
+
+    @Test(timeout = 5 * 60 * 1000)
+    public void testSend10MBMessage() throws Exception {
+        doTestSendLargeMessage(1024 * 1024 * 10);
+    }
+
+    @Test(timeout = 5 * 60 * 1000)
+    public void testSend100MBMessage() throws Exception {
+        doTestSendLargeMessage(1024 * 1024 * 100);
+    }
+
+    public void doTestSendLargeMessage(int expectedSize) throws Exception{
+        LOG.info("doTestSendLargeMessage called with expectedSize " + expectedSize);
+        byte[] payload = createLargePayload(expectedSize);
+        assertEquals(expectedSize, payload.length);
+
+        Connection connection = createAmqpConnection();
+
+        long startTime = System.currentTimeMillis();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        BytesMessage message = session.createBytesMessage();
+        message.writeBytes(payload);
+        producer.send(message);
+        long endTime = System.currentTimeMillis();
+
+        LOG.info("Returned from send after {} ms", endTime - startTime);
+        startTime = System.currentTimeMillis();
+        MessageConsumer consumer = session.createConsumer(queue);
+        connection.start();
+
+        LOG.info("Calling receive");
+        Message received = consumer.receive();
+        assertNotNull(received);
+        assertTrue(received instanceof BytesMessage);
+        BytesMessage bytesMessage = (BytesMessage) received;
+        assertNotNull(bytesMessage);
+        endTime = System.currentTimeMillis();
+
+        LOG.info("Returned from receive after {} ms", endTime - startTime);
+        byte[] bytesReceived = new byte[expectedSize];
+        assertEquals(expectedSize, bytesMessage.readBytes(bytesReceived, expectedSize));
+        assertTrue(Arrays.equals(payload, bytesReceived));
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/keystore
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/keystore b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/keystore
new file mode 100644
index 0000000..9ee6adf
Binary files /dev/null and b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/keystore differ

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/log4j.properties b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/log4j.properties
new file mode 100644
index 0000000..6456126
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/log4j.properties
@@ -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.
+## ---------------------------------------------------------------------------
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, out, stdout
+
+log4j.logger.org.apache.qpid.jms=INFO
+
+# Tune the ActiveMQ and it's AMQP transport as needed for debugging.
+log4j.logger.org.apache.activemq=INFO
+log4j.logger.org.apache.activemq.broker=INFO
+log4j.logger.org.apache.activemq.transport.amqp=INFO
+log4j.logger.org.apache.activemq.transport.amqp.FRAMES=INFO
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/activemq-test.log
+log4j.appender.out.append=true

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/provider.properties
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/provider.properties b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/provider.properties
new file mode 100644
index 0000000..33d06f9
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/provider.properties
@@ -0,0 +1,20 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# This config file is used by the joram jms tests.
+#
+jms.provider.admin.class=org.apache.qpid.jms.joram.ActiveMQAdmin
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/test.properties
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/test.properties b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/test.properties
new file mode 100644
index 0000000..ac4ca8f
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/resources/test.properties
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+timeout=10000
\ No newline at end of file


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


[11/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMessageTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMessageTest.java
new file mode 100644
index 0000000..174ba32
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMessageTest.java
@@ -0,0 +1,944 @@
+/**
+ * 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.jms.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.JmsTopic;
+import org.apache.qpid.jms.message.JmsBytesMessage;
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JmsMessageTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsMessageTest.class);
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    protected boolean readOnlyMessage;
+
+    private String jmsMessageID;
+    private String jmsCorrelationID;
+    private JmsDestination jmsDestination;
+    private JmsDestination jmsReplyTo;
+    private int jmsDeliveryMode;
+    private boolean jmsRedelivered;
+    private String jmsType;
+    private long jmsExpiration;
+    private int jmsPriority;
+    private long jmsTimestamp;
+    private long[] consumerIDs;
+
+    @Before
+    public void setUp() throws Exception {
+        this.jmsMessageID = "ID:TEST-ID:0:0:0:1";
+        this.jmsCorrelationID = "testcorrelationid";
+        this.jmsDestination = new JmsTopic("test.topic");
+        this.jmsReplyTo = new JmsTopic("test.replyto.topic:001");
+        this.jmsDeliveryMode = Message.DEFAULT_DELIVERY_MODE;
+        this.jmsRedelivered = true;
+        this.jmsType = "test type";
+        this.jmsExpiration = 100000;
+        this.jmsPriority = 5;
+        this.jmsTimestamp = System.currentTimeMillis();
+        this.readOnlyMessage = false;
+        this.consumerIDs = new long[3];
+        for (int i = 0; i < this.consumerIDs.length; i++) {
+            this.consumerIDs[i] = i;
+        }
+    }
+
+    @Test
+    public void testHashCode() throws Exception {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSMessageID(this.jmsMessageID);
+        assertTrue(msg.getJMSMessageID().hashCode() == jmsMessageID.hashCode());
+    }
+
+    @Test
+    public void testSetReadOnly() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setReadOnlyProperties(true);
+        boolean test = false;
+        try {
+            msg.setIntProperty("test", 1);
+        } catch (MessageNotWriteableException me) {
+            test = true;
+        } catch (JMSException e) {
+            e.printStackTrace(System.err);
+            test = false;
+        }
+        assertTrue(test);
+    }
+
+    @Test
+    public void testSetToForeignJMSID() throws Exception {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSMessageID("ID:EMS-SERVER.8B443C380083:429");
+    }
+
+    @Test
+    public void testEqualsObject() throws Exception {
+        JmsMessage msg1 = factory.createMessage();
+        JmsMessage msg2 = factory.createMessage();
+        msg1.setJMSMessageID(this.jmsMessageID);
+        assertTrue(!msg1.equals(msg2));
+        msg2.setJMSMessageID(this.jmsMessageID);
+        assertTrue(msg1.equals(msg2));
+    }
+
+    @Test
+    public void testShallowCopy() throws Exception {
+        JmsMessage msg1 = factory.createMessage();
+        msg1.setJMSMessageID(jmsMessageID);
+        JmsMessage msg2 = msg1.copy();
+        assertTrue(msg1 != msg2 && msg1.equals(msg2));
+    }
+
+    @Test
+    public void testCopy() throws Exception {
+        this.jmsMessageID = "testid";
+        this.jmsCorrelationID = "testcorrelationid";
+        this.jmsDestination = new JmsTopic("test.topic");
+        this.jmsReplyTo = new JmsTopic("test.replyto.topic:001");
+        this.jmsDeliveryMode = Message.DEFAULT_DELIVERY_MODE;
+        this.jmsRedelivered = true;
+        this.jmsType = "test type";
+        this.jmsExpiration = 100000;
+        this.jmsPriority = 5;
+        this.jmsTimestamp = System.currentTimeMillis();
+        this.readOnlyMessage = false;
+
+        JmsMessage msg1 = factory.createMessage();
+        msg1.setJMSMessageID(this.jmsMessageID);
+        msg1.setJMSCorrelationID(this.jmsCorrelationID);
+        msg1.setJMSDestination(this.jmsDestination);
+        msg1.setJMSReplyTo(this.jmsReplyTo);
+        msg1.setJMSDeliveryMode(this.jmsDeliveryMode);
+        msg1.setJMSRedelivered(this.jmsRedelivered);
+        msg1.setJMSType(this.jmsType);
+        msg1.setJMSExpiration(this.jmsExpiration);
+        msg1.setJMSPriority(this.jmsPriority);
+        msg1.setJMSTimestamp(this.jmsTimestamp);
+        msg1.setReadOnlyProperties(true);
+        JmsMessage msg2 = msg1.copy();
+        assertEquals(msg1.getJMSMessageID(), msg2.getJMSMessageID());
+        assertTrue(msg1.getJMSCorrelationID().equals(msg2.getJMSCorrelationID()));
+        assertTrue(msg1.getJMSDestination().equals(msg2.getJMSDestination()));
+        assertTrue(msg1.getJMSReplyTo().equals(msg2.getJMSReplyTo()));
+        assertTrue(msg1.getJMSDeliveryMode() == msg2.getJMSDeliveryMode());
+        assertTrue(msg1.getJMSRedelivered() == msg2.getJMSRedelivered());
+        assertTrue(msg1.getJMSType().equals(msg2.getJMSType()));
+        assertTrue(msg1.getJMSExpiration() == msg2.getJMSExpiration());
+        assertTrue(msg1.getJMSPriority() == msg2.getJMSPriority());
+        assertTrue(msg1.getJMSTimestamp() == msg2.getJMSTimestamp());
+
+        LOG.info("Message is:  " + msg1);
+    }
+
+    @Test
+    public void testGetAndSetJMSMessageID() throws Exception {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSMessageID(this.jmsMessageID);
+        assertEquals(msg.getJMSMessageID(), this.jmsMessageID);
+    }
+
+    @Test
+    public void testGetAndSetJMSTimestamp() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSTimestamp(this.jmsTimestamp);
+        assertTrue(msg.getJMSTimestamp() == this.jmsTimestamp);
+    }
+
+    @Test
+    public void testGetJMSCorrelationIDAsBytes() throws Exception {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSCorrelationID(this.jmsCorrelationID);
+        byte[] testbytes = msg.getJMSCorrelationIDAsBytes();
+        String str2 = new String(testbytes);
+        assertTrue(this.jmsCorrelationID.equals(str2));
+    }
+
+    @Test
+    public void testSetJMSCorrelationIDAsBytes() throws Exception {
+        JmsMessage msg = factory.createMessage();
+        byte[] testbytes = this.jmsCorrelationID.getBytes();
+        msg.setJMSCorrelationIDAsBytes(testbytes);
+        testbytes = msg.getJMSCorrelationIDAsBytes();
+        String str2 = new String(testbytes);
+        assertTrue(this.jmsCorrelationID.equals(str2));
+    }
+
+    @Test
+    public void testGetAndSetJMSCorrelationID() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSCorrelationID(this.jmsCorrelationID);
+        assertTrue(msg.getJMSCorrelationID().equals(this.jmsCorrelationID));
+    }
+
+    @Test
+    public void testGetAndSetJMSReplyTo() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSReplyTo(this.jmsReplyTo);
+        assertTrue(msg.getJMSReplyTo().equals(this.jmsReplyTo));
+    }
+
+    @Test
+    public void testGetAndSetJMSDestination() throws Exception {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSDestination(this.jmsDestination);
+        assertTrue(msg.getJMSDestination().equals(this.jmsDestination));
+    }
+
+    @Test
+    public void testGetAndSetJMSDeliveryMode() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSDeliveryMode(this.jmsDeliveryMode);
+        assertTrue(msg.getJMSDeliveryMode() == this.jmsDeliveryMode);
+    }
+
+    @Test
+    public void testGetAndSetMSRedelivered() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSRedelivered(this.jmsRedelivered);
+        assertTrue(msg.getJMSRedelivered() == this.jmsRedelivered);
+    }
+
+    @Test
+    public void testGetAndSetJMSType() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSType(this.jmsType);
+        assertTrue(msg.getJMSType().equals(this.jmsType));
+    }
+
+    @Test
+    public void testGetAndSetJMSExpiration() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSExpiration(this.jmsExpiration);
+        assertTrue(msg.getJMSExpiration() == this.jmsExpiration);
+    }
+
+    @Test
+    public void testGetAndSetJMSPriority() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSPriority(this.jmsPriority);
+        assertTrue(msg.getJMSPriority() == this.jmsPriority);
+
+        msg.setJMSPriority(-90);
+        assertEquals(0, msg.getJMSPriority());
+
+        msg.setJMSPriority(90);
+        assertEquals(9, msg.getJMSPriority());
+    }
+
+    @Test
+    public void testClearProperties() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setStringProperty("test", "test");
+        msg.setJMSMessageID(this.jmsMessageID);
+        msg.clearProperties();
+        assertNull(msg.getStringProperty("test"));
+        assertNotNull(msg.getJMSMessageID());
+    }
+
+    @Test
+    public void testPropertyExists() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setStringProperty("test", "test");
+        assertTrue(msg.propertyExists("test"));
+
+        msg.setIntProperty("JMSXDeliveryCount", 1);
+        assertTrue(msg.propertyExists("JMSXDeliveryCount"));
+    }
+
+    @Test
+    public void testGetBooleanProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "booleanProperty";
+        msg.setBooleanProperty(name, true);
+        assertTrue(msg.getBooleanProperty(name));
+    }
+
+    @Test
+    public void testGetByteProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "byteProperty";
+        msg.setByteProperty(name, (byte) 1);
+        assertTrue(msg.getByteProperty(name) == 1);
+    }
+
+    @Test
+    public void testGetShortProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "shortProperty";
+        msg.setShortProperty(name, (short) 1);
+        assertTrue(msg.getShortProperty(name) == 1);
+    }
+
+    @Test
+    public void testGetIntProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "intProperty";
+        msg.setIntProperty(name, 1);
+        assertTrue(msg.getIntProperty(name) == 1);
+    }
+
+    @Test
+    public void testGetLongProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "longProperty";
+        msg.setLongProperty(name, 1);
+        assertTrue(msg.getLongProperty(name) == 1);
+    }
+
+    @Test
+    public void testGetFloatProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "floatProperty";
+        msg.setFloatProperty(name, 1.3f);
+        assertTrue(msg.getFloatProperty(name) == 1.3f);
+    }
+
+    @Test
+    public void testGetDoubleProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "doubleProperty";
+        msg.setDoubleProperty(name, 1.3d);
+        assertTrue(msg.getDoubleProperty(name) == 1.3);
+    }
+
+    @Test
+    public void testGetStringProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "stringProperty";
+        msg.setStringProperty(name, name);
+        assertTrue(msg.getStringProperty(name).equals(name));
+    }
+
+    @Test
+    public void testGetObjectProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "floatProperty";
+        msg.setFloatProperty(name, 1.3f);
+        assertTrue(msg.getObjectProperty(name) instanceof Float);
+        assertTrue(((Float) msg.getObjectProperty(name)).floatValue() == 1.3f);
+    }
+
+    @Test
+    @SuppressWarnings("rawtypes")
+    public void testGetPropertyNames() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name1 = "floatProperty";
+        msg.setFloatProperty(name1, 1.3f);
+        String name2 = "JMSXDeliveryCount";
+        msg.setIntProperty(name2, 1);
+        String name3 = "JMSRedelivered";
+        msg.setBooleanProperty(name3, false);
+        boolean found1 = false;
+        boolean found2 = false;
+        boolean found3 = false;
+        for (Enumeration iter = msg.getPropertyNames(); iter.hasMoreElements();) {
+            Object element = iter.nextElement();
+            found1 |= element.equals(name1);
+            found2 |= element.equals(name2);
+            found3 |= element.equals(name3);
+        }
+        assertTrue("prop name1 found", found1);
+        // spec compliance, only non JMS (and JMSX) props returned
+        assertFalse("prop name2 not found", found2);
+        assertFalse("prop name4 not found", found3);
+    }
+
+    @Test
+    @SuppressWarnings("rawtypes")
+    public void testGetAllPropertyNames() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name1 = "floatProperty";
+        msg.setFloatProperty(name1, 1.3f);
+        String name2 = "JMSXDeliveryCount";
+        msg.setIntProperty(name2, 1);
+        String name3 = "JMSRedelivered";
+        msg.setBooleanProperty(name3, false);
+        boolean found1 = false;
+        boolean found2 = false;
+        boolean found3 = false;
+        for (Enumeration iter = msg.getAllPropertyNames(); iter.hasMoreElements();) {
+            Object element = iter.nextElement();
+            found1 |= element.equals(name1);
+            found2 |= element.equals(name2);
+            found3 |= element.equals(name3);
+        }
+        assertTrue("prop name1 found", found1);
+        assertTrue("prop name2 found", found2);
+        assertTrue("prop name4 found", found3);
+    }
+
+    @Test
+    public void testSetObjectProperty() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String name = "property";
+
+        try {
+            msg.setObjectProperty(name, "string");
+            msg.setObjectProperty(name, Byte.valueOf("1"));
+            msg.setObjectProperty(name, Short.valueOf("1"));
+            msg.setObjectProperty(name, Integer.valueOf("1"));
+            msg.setObjectProperty(name, Long.valueOf("1"));
+            msg.setObjectProperty(name, Float.valueOf("1.1f"));
+            msg.setObjectProperty(name, Double.valueOf("1.1"));
+            msg.setObjectProperty(name, Boolean.TRUE);
+            msg.setObjectProperty(name, null);
+        } catch (MessageFormatException e) {
+            fail("should accept object primitives and String");
+        }
+        try {
+            msg.setObjectProperty(name, new byte[5]);
+            fail("should accept only object primitives and String");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.setObjectProperty(name, new Object());
+            fail("should accept only object primitives and String");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testConvertProperties() throws Exception {
+
+        JmsMessage msg = factory.createMessage();
+
+        msg.setStringProperty("stringProperty", "string");
+        msg.setByteProperty("byteProperty", Byte.valueOf("1"));
+        msg.setShortProperty("shortProperty", Short.valueOf("1"));
+        msg.setIntProperty("intProperty", Integer.valueOf("1"));
+        msg.setLongProperty("longProperty", Long.valueOf("1"));
+        msg.setFloatProperty("floatProperty", Float.valueOf("1.1f"));
+        msg.setDoubleProperty("doubleProperty", Double.valueOf("1.1"));
+        msg.setBooleanProperty("booleanProperty", Boolean.TRUE);
+        msg.setObjectProperty("nullProperty", null);
+
+        Map<String, Object> properties = msg.getProperties();
+        assertEquals(properties.get("stringProperty"), "string");
+        assertEquals(((Byte) properties.get("byteProperty")).byteValue(), 1);
+        assertEquals(((Short) properties.get("shortProperty")).shortValue(), 1);
+        assertEquals(((Integer) properties.get("intProperty")).intValue(), 1);
+        assertEquals(((Long) properties.get("longProperty")).longValue(), 1);
+        assertEquals(((Float) properties.get("floatProperty")).floatValue(), 1.1f, 0);
+        assertEquals(((Double) properties.get("doubleProperty")).doubleValue(), 1.1, 0);
+        assertEquals(((Boolean) properties.get("booleanProperty")).booleanValue(), true);
+        assertNull(properties.get("nullProperty"));
+    }
+
+    @Test
+    public void testSetNullProperty() throws JMSException {
+        Message msg = factory.createMessage();
+        String name = "cheese";
+        msg.setStringProperty(name, "Cheddar");
+        assertEquals("Cheddar", msg.getStringProperty(name));
+
+        msg.setStringProperty(name, null);
+        assertEquals(null, msg.getStringProperty(name));
+    }
+
+    @Test
+    public void testSetNullPropertyName() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+
+        try {
+            msg.setStringProperty(null, "Cheese");
+            fail("Should have thrown exception");
+        } catch (IllegalArgumentException e) {
+            LOG.info("Worked, caught: " + e);
+        }
+    }
+
+    @Test
+    public void testSetEmptyPropertyName() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+
+        try {
+            msg.setStringProperty("", "Cheese");
+            fail("Should have thrown exception");
+        } catch (IllegalArgumentException e) {
+            LOG.info("Worked, caught: " + e);
+        }
+    }
+
+    @Test
+    public void testGetAndSetJMSXDeliveryCount() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setIntProperty("JMSXDeliveryCount", 1);
+        int count = msg.getIntProperty("JMSXDeliveryCount");
+        assertTrue("expected delivery count = 1 - got: " + count, count == 1);
+    }
+
+    @Test
+    public void testClearBody() throws JMSException {
+        JmsBytesMessage message = factory.createBytesMessage();
+        message.clearBody();
+        assertFalse(message.isReadOnlyBody());
+        assertNull(message.getContent());
+    }
+
+    @Test
+    public void testBooleanPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setBooleanProperty(propertyName, true);
+
+        assertEquals(((Boolean) msg.getObjectProperty(propertyName)).booleanValue(), true);
+        assertTrue(msg.getBooleanProperty(propertyName));
+        assertEquals(msg.getStringProperty(propertyName), "true");
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getIntProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getLongProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testBytePropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setByteProperty(propertyName, (byte) 1);
+
+        assertEquals(((Byte) msg.getObjectProperty(propertyName)).byteValue(), 1);
+        assertEquals(msg.getByteProperty(propertyName), 1);
+        assertEquals(msg.getShortProperty(propertyName), 1);
+        assertEquals(msg.getIntProperty(propertyName), 1);
+        assertEquals(msg.getLongProperty(propertyName), 1);
+        assertEquals(msg.getStringProperty(propertyName), "1");
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testShortPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setShortProperty(propertyName, (short) 1);
+
+        assertEquals(((Short) msg.getObjectProperty(propertyName)).shortValue(), 1);
+        assertEquals(msg.getShortProperty(propertyName), 1);
+        assertEquals(msg.getIntProperty(propertyName), 1);
+        assertEquals(msg.getLongProperty(propertyName), 1);
+        assertEquals(msg.getStringProperty(propertyName), "1");
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testIntPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setIntProperty(propertyName, 1);
+
+        assertEquals(((Integer) msg.getObjectProperty(propertyName)).intValue(), 1);
+        assertEquals(msg.getIntProperty(propertyName), 1);
+        assertEquals(msg.getLongProperty(propertyName), 1);
+        assertEquals(msg.getStringProperty(propertyName), "1");
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testLongPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setLongProperty(propertyName, 1);
+
+        assertEquals(((Long) msg.getObjectProperty(propertyName)).longValue(), 1);
+        assertEquals(msg.getLongProperty(propertyName), 1);
+        assertEquals(msg.getStringProperty(propertyName), "1");
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getIntProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testFloatPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setFloatProperty(propertyName, (float) 1.5);
+        assertEquals(((Float) msg.getObjectProperty(propertyName)).floatValue(), 1.5, 0);
+        assertEquals(msg.getFloatProperty(propertyName), 1.5, 0);
+        assertEquals(msg.getDoubleProperty(propertyName), 1.5, 0);
+        assertEquals(msg.getStringProperty(propertyName), "1.5");
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getIntProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getLongProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testDoublePropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setDoubleProperty(propertyName, 1.5);
+        assertEquals(((Double) msg.getObjectProperty(propertyName)).doubleValue(), 1.5, 0);
+        assertEquals(msg.getDoubleProperty(propertyName), 1.5, 0);
+        assertEquals(msg.getStringProperty(propertyName), "1.5");
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getIntProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getLongProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+    }
+
+    @Test
+    public void testStringPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        String stringValue = "true";
+        msg.setStringProperty(propertyName, stringValue);
+        assertEquals(msg.getStringProperty(propertyName), stringValue);
+        assertEquals(msg.getObjectProperty(propertyName), stringValue);
+        assertEquals(msg.getBooleanProperty(propertyName), true);
+
+        stringValue = "1";
+        msg.setStringProperty(propertyName, stringValue);
+        assertEquals(msg.getByteProperty(propertyName), 1);
+        assertEquals(msg.getShortProperty(propertyName), 1);
+        assertEquals(msg.getIntProperty(propertyName), 1);
+        assertEquals(msg.getLongProperty(propertyName), 1);
+
+        stringValue = "1.5";
+        msg.setStringProperty(propertyName, stringValue);
+        assertEquals(msg.getFloatProperty(propertyName), 1.5, 0);
+        assertEquals(msg.getDoubleProperty(propertyName), 1.5, 0);
+
+        stringValue = "bad";
+        msg.setStringProperty(propertyName, stringValue);
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (NumberFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (NumberFormatException e) {
+        }
+        try {
+            msg.getIntProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (NumberFormatException e) {
+        }
+        try {
+            msg.getLongProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (NumberFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (NumberFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (NumberFormatException e) {
+        }
+        assertFalse(msg.getBooleanProperty(propertyName));
+    }
+
+    @Test
+    public void testObjectPropertyConversion() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        Object obj = new Object();
+        try {
+            msg.setProperty(propertyName, obj);
+        } catch (Exception e) {
+        }
+        try {
+            msg.getStringProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getBooleanProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getByteProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getShortProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getIntProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getLongProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getFloatProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+        try {
+            msg.getDoubleProperty(propertyName);
+            fail("Should have thrown exception");
+        } catch (MessageFormatException e) {
+        }
+
+    }
+
+    @Test
+    public void testReadOnlyProperties() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        String propertyName = "property";
+        msg.setReadOnlyProperties(true);
+
+        try {
+            msg.setObjectProperty(propertyName, new Object());
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setStringProperty(propertyName, "test");
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setBooleanProperty(propertyName, true);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setByteProperty(propertyName, (byte) 1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setShortProperty(propertyName, (short) 1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setIntProperty(propertyName, 1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setLongProperty(propertyName, 1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setFloatProperty(propertyName, (float) 1.5);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+        try {
+            msg.setDoubleProperty(propertyName, 1.5);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException e) {
+        }
+    }
+
+    @Test
+    public void testIsExpired() throws JMSException {
+        JmsMessage msg = factory.createMessage();
+        msg.setJMSExpiration(System.currentTimeMillis() - 1);
+        assertTrue(msg.isExpired());
+        msg.setJMSExpiration(System.currentTimeMillis() + 10000);
+        assertFalse(msg.isExpired());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsObjectMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsObjectMessageTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsObjectMessageTest.java
new file mode 100644
index 0000000..b5e2e98
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsObjectMessageTest.java
@@ -0,0 +1,260 @@
+/**
+ * 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.jms.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.ObjectMessage;
+
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsObjectMessage;
+import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultObjectMessageFacade;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ *
+ */
+public class JmsObjectMessageTest {
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    /**
+     * Test that attempting to write bytes to a received message (without calling {@link ObjectMessage#clearBody()} first)
+     * causes a {@link MessageNotWriteableException} to be thrown due to being read-only.
+     */
+    @Test
+    public void testReceivedObjectMessageThrowsMessageNotWriteableExceptionOnSetObject() throws Exception {
+        String content = "myStringContent";
+        JmsObjectMessageFacade facade = new JmsDefaultObjectMessageFacade();
+        facade.setObject(content);
+        JmsObjectMessage objectMessage = new JmsObjectMessage(facade);
+        objectMessage.onSend();
+
+        try {
+            objectMessage.setObject("newObject");
+            fail("Expected exception to be thrown");
+        } catch (MessageNotWriteableException mnwe) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link ObjectMessage#clearBody()} causes a received
+     * message to become writable
+     */
+    @Test
+    public void testClearBodyOnReceivedObjectMessageMakesMessageWritable() throws Exception {
+        String content = "myStringContent";
+        JmsObjectMessageFacade facade = new JmsDefaultObjectMessageFacade();
+        facade.setObject(content);
+        JmsObjectMessage objectMessage = new JmsObjectMessage(facade);
+        objectMessage.onSend();
+
+        assertTrue("Message should not be writable", objectMessage.isReadOnlyBody());
+        objectMessage.clearBody();
+        assertFalse("Message should be writable", objectMessage.isReadOnlyBody());
+    }
+
+    /**
+     * Test that calling {@link ObjectMessage#clearBody()} of a received message
+     * causes the body of the underlying {@link AmqpObjectMessage} to be emptied.
+     */
+    @Test
+    public void testClearBodyOnReceivedObjectMessageClearsUnderlyingMessageBody() throws Exception {
+        String content = "myStringContent";
+        JmsDefaultObjectMessageFacade facade = new JmsDefaultObjectMessageFacade();
+        facade.setObject(content);
+        JmsObjectMessage objectMessage = new JmsObjectMessage(facade);
+        objectMessage.onSend();
+
+        assertNotNull("Expected body section but none was present", facade.getSerializedObject());
+        objectMessage.clearBody();
+
+        // check that the returned object is now null
+        assertNull("Unexpected object value", objectMessage.getObject());
+
+        // verify the underlying message facade has no body
+        assertNull("Expected no body section", facade.getSerializedObject());
+    }
+
+    /**
+     * Test that setting an object on a new message and later getting the value, returns an
+     * equal but different object that does not pick up intermediate changes to the set object.
+     */
+    @Test
+    public void testSetThenGetObjectReturnsSnapshot() throws Exception
+    {
+        Map<String,String> origMap = new HashMap<String,String>();
+        origMap.put("key1", "value1");
+
+        JmsDefaultObjectMessageFacade facade = new JmsDefaultObjectMessageFacade();
+        facade.setObject((Serializable) origMap);
+        JmsObjectMessage objectMessage = new JmsObjectMessage(facade);
+        objectMessage.onSend();
+
+        // verify we get a different-but-equal object back
+        Serializable serialized = objectMessage.getObject();
+        assertTrue("Unexpected object type returned", serialized instanceof Map<?,?>);
+        Map<?,?> returnedObject1 = (Map<?,?>) serialized;
+        assertNotSame("Expected different objects, due to snapshot being taken", origMap, returnedObject1);
+        assertEquals("Expected equal objects, due to snapshot being taken", origMap, returnedObject1);
+
+        // mutate the original object
+        origMap.put("key2", "value2");
+
+        // verify we get a different-but-equal object back when compared to the previously retrieved object
+        Serializable serialized2 = objectMessage.getObject();
+        assertTrue("Unexpected object type returned", serialized2 instanceof Map<?,?>);
+        Map<?,?> returnedObject2 = (Map<?,?>) serialized2;
+        assertNotSame("Expected different objects, due to snapshot being taken", origMap, returnedObject2);
+        assertEquals("Expected equal objects, due to snapshot being taken", returnedObject1, returnedObject2);
+
+        // verify the mutated map is a different and not equal object
+        assertNotSame("Expected different objects, due to snapshot being taken", returnedObject1, returnedObject2);
+        assertNotEquals("Expected objects to differ, due to snapshot being taken", origMap, returnedObject2);
+    }
+
+    /**
+     * Test that setting an object on a new message which contains non-serializable content results
+     * in an {@link MessageFormatException} being thrown due to failure to encode the object.
+     */
+    @Test
+    public void testSetObjectWithNonSerializableThrowsJMSMFE() throws Exception {
+        Map<String, Object> origMap = new HashMap<String, Object>();
+        origMap.put("key1", "value1");
+        origMap.put("notSerializable", new NotSerializable());
+
+        JmsObjectMessage objectMessage = factory.createObjectMessage();
+
+        try {
+            objectMessage.setObject((Serializable) origMap);
+            fail("Expected exception to be thrown");
+        } catch (MessageFormatException mfe) {
+            // expected
+        }
+    }
+
+    //Test class
+    private static class NotSerializable
+    {
+        public NotSerializable()
+        {
+        }
+    }
+
+    /**
+     * Test that failure during deserialization of an object in a message results
+     * in an {@link MessageFormatException} being throw.
+     */
+    @Test(expected=MessageFormatException.class)
+    public void testGetObjectWithFailedDeserialisationThrowsJMSMFE() throws Exception {
+        JmsObjectMessageFacade facade = Mockito.mock(JmsDefaultObjectMessageFacade.class);
+        Mockito.when(facade.getObject()).thenThrow(new ClassCastException("Failed to get object"));
+        JmsObjectMessage objectMessage = new JmsObjectMessage(facade);
+        objectMessage.getObject();
+    }
+
+    @Test
+    public void testBytes() throws JMSException, IOException {
+        JmsObjectMessage msg = factory.createObjectMessage();
+        String str = "testText";
+        msg.setObject(str);
+
+        msg = msg.copy();
+        assertEquals(msg.getObject(), str);
+    }
+
+    @Test
+    public void testSetObject() throws JMSException {
+        JmsObjectMessage msg = factory.createObjectMessage();
+        String str = "testText";
+        msg.setObject(str);
+        assertEquals(str, msg.getObject());
+    }
+
+    @Test
+    public void testClearBody() throws JMSException {
+        JmsObjectMessage objectMessage = factory.createObjectMessage();
+        try {
+            objectMessage.setObject("String");
+            objectMessage.clearBody();
+            assertFalse(objectMessage.isReadOnlyBody());
+            assertNull(objectMessage.getObject());
+            objectMessage.setObject("String");
+            objectMessage.getObject();
+        } catch (MessageNotWriteableException mnwe) {
+            fail("should be writeable");
+        }
+    }
+
+    @Test
+    public void testReadOnlyBody() throws JMSException {
+        JmsObjectMessage msg = factory.createObjectMessage();
+        msg.setObject("test");
+        msg.setReadOnlyBody(true);
+        try {
+            msg.getObject();
+        } catch (MessageNotReadableException e) {
+            fail("should be readable");
+        }
+        try {
+            msg.setObject("test");
+            fail("should throw exception");
+        } catch (MessageNotWriteableException e) {
+        }
+    }
+
+    @Test
+    public void testWriteOnlyBody() throws JMSException { // should always be readable
+        JmsObjectMessage msg = factory.createObjectMessage();
+        msg.setReadOnlyBody(false);
+        try {
+            msg.setObject("test");
+            msg.getObject();
+        } catch (MessageNotReadableException e) {
+            fail("should be readable");
+        }
+        msg.setReadOnlyBody(true);
+        try {
+            msg.getObject();
+            msg.setObject("test");
+            fail("should throw exception");
+        } catch (MessageNotReadableException e) {
+            fail("should be readable");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+    }
+}


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


[05/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgent.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgent.java
new file mode 100644
index 0000000..b2daca2
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgent.java
@@ -0,0 +1,391 @@
+/**
+ * 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.jms.provider.discovery.multicast;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.qpid.jms.provider.discovery.DiscoveryAgent;
+import org.apache.qpid.jms.provider.discovery.DiscoveryEvent;
+import org.apache.qpid.jms.provider.discovery.DiscoveryEvent.EventType;
+import org.apache.qpid.jms.provider.discovery.DiscoveryListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Discovery agent that listens on a multicast address for new Broker advisories.
+ */
+public class MulticastDiscoveryAgent implements DiscoveryAgent, Runnable {
+
+    public static final String DEFAULT_DISCOVERY_URI_STRING = "multicast://239.255.2.3:6155";
+    public static final String DEFAULT_HOST_STR = "default";
+    public static final String DEFAULT_HOST_IP = System.getProperty("qpidjms.partition.discovery", "239.255.2.3");
+    public static final int DEFAULT_PORT = 6155;
+
+    private static final Logger LOG = LoggerFactory.getLogger(MulticastDiscoveryAgent.class);
+    private static final int BUFF_SIZE = 8192;
+    private static final int DEFAULT_IDLE_TIME = 500;
+    private static final int HEARTBEAT_MISS_BEFORE_DEATH = 10;
+
+    private DiscoveryListener listener;
+    private URI discoveryURI;
+    private int timeToLive = 1;
+    private boolean loopBackMode;
+    private final Map<String, RemoteBrokerData> brokersByService = new ConcurrentHashMap<String, RemoteBrokerData>();
+    private String group = "default";
+    private InetAddress inetAddress;
+    private SocketAddress sockAddress;
+    private MulticastSocket mcast;
+    private Thread runner;
+    private long keepAliveInterval = DEFAULT_IDLE_TIME;
+    private String mcInterface;
+    private String mcNetworkInterface;
+    private String mcJoinNetworkInterface;
+    private String service;
+    private final AtomicBoolean started = new AtomicBoolean(false);
+    private PacketParser parser;
+
+    public MulticastDiscoveryAgent(URI discoveryURI) {
+        this.discoveryURI = discoveryURI;
+    }
+
+    @Override
+    public void setDiscoveryListener(DiscoveryListener listener) {
+        this.listener = listener;
+    }
+
+    public DiscoveryListener getDiscoveryListener() {
+        return this.listener;
+    }
+
+    @Override
+    public void start() throws IOException, IllegalStateException {
+        if (listener == null) {
+            throw new IllegalStateException("No DiscoveryListener configured.");
+        }
+
+        if (started.compareAndSet(false, true)) {
+
+            if (group == null || group.length() == 0) {
+                throw new IOException("You must specify a group to discover");
+            }
+
+            if (discoveryURI == null) {
+                try {
+                    discoveryURI = new URI(DEFAULT_DISCOVERY_URI_STRING);
+                } catch (URISyntaxException e) {
+                    // Default is always valid.
+                }
+            }
+
+            LOG.trace("mcast - discoveryURI = {}", discoveryURI);
+
+            String myHost = discoveryURI.getHost();
+            int myPort = discoveryURI.getPort();
+
+            if (DEFAULT_HOST_STR.equals(myHost)) {
+                myHost = DEFAULT_HOST_IP;
+            }
+
+            if (myPort < 0) {
+                myPort = DEFAULT_PORT;
+            }
+
+            LOG.trace("mcast - myHost = {}", myHost);
+            LOG.trace("mcast - myPort = {}", myPort);
+            LOG.trace("mcast - group = {}", group);
+            LOG.trace("mcast - interface = {}", mcInterface);
+            LOG.trace("mcast - network interface = {}", mcNetworkInterface);
+            LOG.trace("mcast - join network interface = {}", mcJoinNetworkInterface);
+
+            this.inetAddress = InetAddress.getByName(myHost);
+            this.sockAddress = new InetSocketAddress(this.inetAddress, myPort);
+            mcast = new MulticastSocket(myPort);
+            mcast.setLoopbackMode(loopBackMode);
+            mcast.setTimeToLive(getTimeToLive());
+            if (mcJoinNetworkInterface != null) {
+                mcast.joinGroup(sockAddress, NetworkInterface.getByName(mcJoinNetworkInterface));
+            } else {
+                mcast.joinGroup(inetAddress);
+            }
+            mcast.setSoTimeout((int) keepAliveInterval);
+            if (mcInterface != null) {
+                mcast.setInterface(InetAddress.getByName(mcInterface));
+            }
+            if (mcNetworkInterface != null) {
+                mcast.setNetworkInterface(NetworkInterface.getByName(mcNetworkInterface));
+            }
+            runner = new Thread(this);
+            runner.setName(this.toString() + ":" + runner.getName());
+            runner.setDaemon(true);
+            runner.start();
+        }
+    }
+
+    @Override
+    public void close() {
+        if (started.compareAndSet(true, false)) {
+            if (mcast != null) {
+                mcast.close();
+            }
+            if (runner != null) {
+                runner.interrupt();
+            }
+        }
+    }
+
+    @Override
+    public void suspend() {
+        // We don't suspend multicast as it's mostly a passive listener.
+    }
+
+    @Override
+    public void resume() {
+        // We don't suspend multicast as it's mostly a passive listener.
+    }
+
+    @Override
+    public void run() {
+        byte[] buf = new byte[BUFF_SIZE];
+        DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
+        while (started.get()) {
+            expireOldServices();
+            try {
+                mcast.receive(packet);
+                if (packet.getLength() > 0) {
+                    DiscoveryEvent event = parser.processPacket(packet.getData(), packet.getOffset(), packet.getLength());
+                    if (event != null) {
+                        if (event.getType() == EventType.ALIVE) {
+                            processAlive(event);
+                        } else {
+                            processShutdown(event);
+                        }
+                    }
+                }
+            } catch (SocketTimeoutException se) {
+                // ignore
+            } catch (IOException e) {
+                if (started.get()) {
+                    LOG.error("failed to process packet: {}", e.getMessage());
+                    LOG.trace(" packet processing failed by: {}", e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "MulticastDiscoveryAgent: listener:" + getDiscvoeryURI();
+    }
+
+    //---------- Internal Implementation -------------------------------------//
+
+    private void processAlive(DiscoveryEvent event) {
+        RemoteBrokerData data = brokersByService.get(event.getPeerUri());
+        if (data == null) {
+            String peerUri = event.getPeerUri();
+            data = new RemoteBrokerData(event.getPeerUri());
+            brokersByService.put(peerUri, data);
+            fireServiceAddEvent(data);
+        } else {
+            data.updateHeartBeat();
+        }
+    }
+
+    private void processShutdown(DiscoveryEvent event) {
+        RemoteBrokerData data = brokersByService.remove(event.getPeerUri());
+        if (data != null) {
+            fireServiceRemovedEvent(data);
+        }
+    }
+
+    private void expireOldServices() {
+        long expireTime = System.currentTimeMillis() - (keepAliveInterval * HEARTBEAT_MISS_BEFORE_DEATH);
+        for (Iterator<RemoteBrokerData> i = brokersByService.values().iterator(); i.hasNext();) {
+            RemoteBrokerData data = i.next();
+            if (data.getLastHeartBeat() < expireTime) {
+                processShutdown(data.asShutdownEvent());
+            }
+        }
+    }
+
+    private void fireServiceRemovedEvent(final RemoteBrokerData data) {
+        if (listener != null && started.get()) {
+            listener.onServiceRemove(data);
+        }
+    }
+
+    private void fireServiceAddEvent(final RemoteBrokerData data) {
+        if (listener != null && started.get()) {
+            listener.onServiceAdd(data);
+        }
+    }
+
+    // ---------- Property Accessors ------------------------------------------//
+
+    /**
+     * @return the original URI used to create the Discovery Agent.
+     */
+    public URI getDiscvoeryURI() {
+        return this.discoveryURI;
+    }
+
+    /**
+     * @return Returns the loopBackMode.
+     */
+    public boolean isLoopBackMode() {
+        return loopBackMode;
+    }
+
+    /**
+     * @param loopBackMode
+     *        The loopBackMode to set.
+     */
+    public void setLoopBackMode(boolean loopBackMode) {
+        this.loopBackMode = loopBackMode;
+    }
+
+    /**
+     * @return Returns the timeToLive.
+     */
+    public int getTimeToLive() {
+        return timeToLive;
+    }
+
+    /**
+     * @param timeToLive
+     *        The timeToLive to set.
+     */
+    public void setTimeToLive(int timeToLive) {
+        this.timeToLive = timeToLive;
+    }
+
+    public long getKeepAliveInterval() {
+        return keepAliveInterval;
+    }
+
+    public void setKeepAliveInterval(long keepAliveInterval) {
+        this.keepAliveInterval = keepAliveInterval;
+    }
+
+    public void setInterface(String mcInterface) {
+        this.mcInterface = mcInterface;
+    }
+
+    public void setNetworkInterface(String mcNetworkInterface) {
+        this.mcNetworkInterface = mcNetworkInterface;
+    }
+
+    public void setJoinNetworkInterface(String mcJoinNetwrokInterface) {
+        this.mcJoinNetworkInterface = mcJoinNetwrokInterface;
+    }
+
+    /**
+     * @return the multicast group this agent is assigned to.
+     */
+    public String getGroup() {
+        return this.group;
+    }
+
+    /**
+     * Sets the multicast group this agent is assigned to.  The group can only be set
+     * prior to starting the agent, once started the group change will never take effect.
+     *
+     * @param group
+     *        the multicast group the agent is assigned to.
+     */
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    /**
+     * Returns the name of the service that is providing the discovery data for this agent such
+     * as ActiveMQ.
+     *
+     * @return the name of the service that is advertising remote peer data.
+     */
+    public String getService() {
+        return this.service;
+    }
+
+    /**
+     * Sets the name of the service that is providing the remote peer discovery data.
+     *
+     * @param name
+     *        the name of the service that provides this agent with remote peer data.
+     */
+    public void setService(String name) {
+        this.service = name;
+    }
+
+    /**
+     * @return the currently configured datagram packet parser for this agent.
+     */
+    public PacketParser getParser() {
+        return parser;
+    }
+
+    /**
+     * Sets the datagram packet parser used to read the discovery data broadcast by the service
+     * being monitored for remote peers.
+     *
+     * @param parser
+     *        the datagram packet parser to use.
+     */
+    public void setParser(PacketParser parser) {
+        this.parser = parser;
+    }
+
+    // ---------- Discovered Peer Bookkeeping Class ---------------------------//
+
+    private class RemoteBrokerData extends DiscoveryEvent {
+
+        long lastHeartBeat;
+
+        public RemoteBrokerData(String peerUri) {
+            super(peerUri, EventType.ALIVE);
+            this.lastHeartBeat = System.currentTimeMillis();
+        }
+
+        /**
+         * @return an event representing this remote peers shutdown event.
+         */
+        public DiscoveryEvent asShutdownEvent() {
+            return new DiscoveryEvent(getPeerUri(), EventType.SHUTDOWN);
+        }
+
+        public synchronized void updateHeartBeat() {
+            lastHeartBeat = System.currentTimeMillis();
+        }
+
+        public synchronized long getLastHeartBeat() {
+            return lastHeartBeat;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgentFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgentFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgentFactory.java
new file mode 100644
index 0000000..6730f33
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/MulticastDiscoveryAgentFactory.java
@@ -0,0 +1,57 @@
+/**
+ * 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.jms.provider.discovery.multicast;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.qpid.jms.provider.discovery.DiscoveryAgent;
+import org.apache.qpid.jms.provider.discovery.DiscoveryAgentFactory;
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+
+/**
+ * Creates and configures a new instance of the mutlicast agent.
+ */
+public class MulticastDiscoveryAgentFactory extends DiscoveryAgentFactory {
+
+    private static final String DEFAULT_SERVICE = "activemq";
+
+    @Override
+    public DiscoveryAgent createDiscoveryAgent(URI discoveryURI) throws Exception {
+        MulticastDiscoveryAgent agent = new MulticastDiscoveryAgent(discoveryURI);
+        Map<String, String> options = URISupport.parseParameters(discoveryURI);
+        PropertyUtil.setProperties(agent, options);
+
+        String service = agent.getService();
+        if (service == null || service.isEmpty()) {
+            service = DEFAULT_SERVICE;
+        }
+
+        PacketParser packetParser = PacketParserFactory.createAgent(service);
+        packetParser.setGroup(agent.getGroup());
+
+        agent.setParser(packetParser);
+
+        return agent;
+    }
+
+    @Override
+    public String getName() {
+        return "multicast";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParser.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParser.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParser.java
new file mode 100644
index 0000000..294234e
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParser.java
@@ -0,0 +1,55 @@
+/**
+ * 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.jms.provider.discovery.multicast;
+
+import org.apache.qpid.jms.provider.discovery.DiscoveryEvent;
+
+/**
+ * Interface for a DatagramPacket parser object which is used by the
+ * MulticastDiscoveryAget to parse incoming packets to determine the
+ * discovered peer information.
+ */
+public interface PacketParser {
+
+    /**
+     * @return the multicast group assignment for this parser.
+     */
+    String getGroup();
+
+    /**
+     * Sets the multicast group that the parent agent is assigned to.  This can
+     * be used in some cases to parse discovery messages.
+     *
+     * @param group
+     *        the multicast group that this parser's parent agent resides in./
+     */
+    void setGroup(String group);
+
+    /**
+     * Process in incoming event packet and create a DiscoveryEvent from the data.
+     *
+     * @param data
+     *        the new data packet to process.
+     * @param offset
+     *        the offset into the data buffer to start at.
+     * @param length
+     *        the length of the data packet contained in the buffer.
+     *
+     * @return a new DiscoveryEvent created from pocessing the incoming data.
+     */
+    DiscoveryEvent processPacket(byte[] data, int offset, int length);
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParserFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParserFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParserFactory.java
new file mode 100644
index 0000000..c69b78d
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/PacketParserFactory.java
@@ -0,0 +1,110 @@
+/**
+ * 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.jms.provider.discovery.multicast;
+
+import java.io.IOException;
+
+import org.apache.qpid.jms.util.FactoryFinder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory used to find and create instances of DiscoveryAgent using the name
+ * of the desired agent to locate it's factory class definition file.
+ */
+public abstract class PacketParserFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PacketParserFactory.class);
+
+    private static final FactoryFinder<PacketParserFactory> AGENT_FACTORY_FINDER =
+        new FactoryFinder<PacketParserFactory>(
+            PacketParserFactory.class,
+            "META-INF/services/org/apache/qpid/jms/provider/agents/multicast-parsers/");
+
+    /**
+     * Creates an instance of the given PacketParser
+     *
+     * @param key
+     *        the name of the required packet parser for the agent.
+     *
+     * @return a new PacketParser instance.
+     *
+     * @throws Exception if an error occurs while creating the PacketParser instance.
+     */
+    public abstract PacketParser createPacketParser(String key) throws Exception;
+
+    /**
+     * @return the name of this packet parser, e.g ActiveMQ.
+     */
+    public abstract String getName();
+
+    /**
+     * Static create method that performs the PacketParser search and handles the
+     * configuration and setup.
+     *
+     * @param key
+     *        the name of the desired PacketParser type.
+     *
+     * @return a new PacketParser instance that is ready for use.
+     *
+     * @throws Exception if an error occurs while creating the PacketParser instance.
+     */
+    public static PacketParser createAgent(String key) throws Exception {
+        PacketParser result = null;
+
+        try {
+            PacketParserFactory factory = findAgentFactory(key);
+            result = factory.createPacketParser(key);
+        } catch (Exception ex) {
+            LOG.error("Failed to create PacketParserFactory instance for: {}", key);
+            LOG.trace("Error: ", ex);
+            throw ex;
+        }
+
+        return result;
+    }
+
+    /**
+     * Searches for a PacketParserFactory by using the given key.
+     *
+     * The search first checks the local cache of packet parser factories before moving on
+     * to search in the classpath.
+     *
+     * @param key
+     *        The name of the PacketParserFactory that should be located.
+     *
+     * @return a PacketParserFactory instance matching the given key.
+     *
+     * @throws IOException if an error occurs while locating the factory.
+     */
+    protected static PacketParserFactory findAgentFactory(String key) throws IOException {
+        if (key == null) {
+            throw new IOException("No PacketParserFactory name specified: [" + key + "]");
+        }
+
+        PacketParserFactory factory = null;
+        if (factory == null) {
+            try {
+                factory = AGENT_FACTORY_FINDER.newInstance(key);
+            } catch (Throwable e) {
+                throw new IOException("Discovery Agent scheme NOT recognized: [" + key + "]", e);
+            }
+        }
+
+        return factory;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParser.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParser.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParser.java
new file mode 100644
index 0000000..1cb2935
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParser.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.jms.provider.discovery.multicast.parsers;
+
+import org.apache.qpid.jms.provider.discovery.DiscoveryEvent;
+import org.apache.qpid.jms.provider.discovery.DiscoveryEvent.EventType;
+import org.apache.qpid.jms.provider.discovery.multicast.PacketParser;
+
+/**
+ * Parser instance for ActiveMQ multicast discovery processing.
+ */
+public class ActiveMQPacketParser implements PacketParser {
+
+    private static final String TYPE_SUFFIX = "ActiveMQ-4.";
+    private static final String ALIVE = "alive.";
+    private static final String DEAD = "dead.";
+    private static final String DELIMITER = "%";
+
+    private String group;
+
+    @Override
+    public String getGroup() {
+        return this.group;
+    }
+
+    @Override
+    public void setGroup(String group) {
+        this.group = group;
+    }
+
+    @Override
+    public DiscoveryEvent processPacket(byte[] packet, int offset, int length) {
+        String str = new String(packet, offset, length);
+        DiscoveryEvent event = null;
+        if (str.startsWith(getType())) {
+            String payload = str.substring(getType().length());
+            if (payload.startsWith(ALIVE)) {
+                String brokerName = getBrokerName(payload.substring(ALIVE.length()));
+                String brokerUri = payload.substring(ALIVE.length() + brokerName.length() + 2);
+                event = new DiscoveryEvent(brokerUri, EventType.ALIVE);
+            } else {
+                String brokerName = getBrokerName(payload.substring(DEAD.length()));
+                String brokerUri = payload.substring(DEAD.length() + brokerName.length() + 2);
+                event = new DiscoveryEvent(brokerUri, EventType.SHUTDOWN);
+            }
+        }
+        return event;
+    }
+
+    private String getBrokerName(String str) {
+        String result = null;
+        int start = str.indexOf(DELIMITER);
+        if (start >= 0) {
+            int end = str.indexOf(DELIMITER, start + 1);
+            result = str.substring(start + 1, end);
+        }
+        return result;
+    }
+
+    private String getType() {
+        return group + "." + TYPE_SUFFIX;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParserFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParserFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParserFactory.java
new file mode 100644
index 0000000..67f8a48
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/multicast/parsers/ActiveMQPacketParserFactory.java
@@ -0,0 +1,42 @@
+/**
+ * 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.jms.provider.discovery.multicast.parsers;
+
+import org.apache.qpid.jms.provider.discovery.multicast.PacketParser;
+import org.apache.qpid.jms.provider.discovery.multicast.PacketParserFactory;
+
+/**
+ * Factory class for the ActiveMQ Packet Parser used to process data set over
+ * multicast when discovering ActiveMQ Brokers.
+ */
+public class ActiveMQPacketParserFactory extends PacketParserFactory {
+
+    @Override
+    public PacketParser createPacketParser(String key) throws Exception {
+        return new ActiveMQPacketParser();
+    }
+
+    @Override
+    public String getName() {
+        return "ActiveMQ";
+    }
+
+    @Override
+    public String toString() {
+        return getName() + ": Discovery Parser.";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast b/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast
new file mode 100644
index 0000000..1fdf0b2
--- /dev/null
+++ b/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.discovery.multicast.MulticastDiscoveryAgentFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast-parsers/activemq
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast-parsers/activemq b/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast-parsers/activemq
new file mode 100644
index 0000000..8278f11
--- /dev/null
+++ b/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/agents/multicast-parsers/activemq
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.discovery.multicast.parsers.ActiveMQPacketParserFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/discovery
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/discovery b/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/discovery
new file mode 100644
index 0000000..a5b8170
--- /dev/null
+++ b/qpid-jms-discovery/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/discovery
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.discovery.DiscoveryProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-examples/.gitignore
----------------------------------------------------------------------
diff --git a/qpid-jms-examples/.gitignore b/qpid-jms-examples/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/qpid-jms-examples/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-examples/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-examples/pom.xml b/qpid-jms-examples/pom.xml
new file mode 100644
index 0000000..bd2b656
--- /dev/null
+++ b/qpid-jms-examples/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>qpid-jms-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>qpid-jms-examples</artifactId>
+  <packaging>jar</packaging>
+  <name>QpidJMS Examples</name>
+  <description>Examples for QpidJMS</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-jms-client</artifactId>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Drain.java
----------------------------------------------------------------------
diff --git a/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Drain.java b/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Drain.java
new file mode 100644
index 0000000..9e8ffa5
--- /dev/null
+++ b/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Drain.java
@@ -0,0 +1,139 @@
+/*
+ *
+ * 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.jms.example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.MessageConsumer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+
+public class Drain
+{
+    private static final String DEFAULT_USER = "guest";
+    private static final String DEFAULT_PASSWORD = "guest";
+    private static final int DEFAULT_PORT = 5672;
+    private static final String DEFAULT_HOST = "localhost";
+    private static final int DEFAULT_COUNT = 10000;
+
+    private String _hostname;
+    private int _port;
+    private int _count;
+    private String _username;
+    private String _password;
+    private String _queuePrefix;
+
+    public Drain(int count, String hostname, int port, String queuePrefix)
+    {
+        _count = count;
+        _hostname = hostname;
+        _port = port;
+        _username = DEFAULT_USER;
+        _password = DEFAULT_PASSWORD;
+        _queuePrefix = queuePrefix;
+    }
+
+    public void runExample()
+    {
+        try
+        {
+            //TODO: use JNDI lookup rather than direct instantiation
+            JmsConnectionFactory factory = new JmsConnectionFactory("amqp://" + _hostname + ":" + _port);
+            if(_queuePrefix != null)
+            {
+                //TODO: use URL options?
+                factory.setQueuePrefix(_queuePrefix);
+            }
+
+            Connection connection = factory.createConnection(_username,_password);
+            connection.start();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+            Destination queue = session.createQueue("myQueue");
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+
+            long start = System.currentTimeMillis();
+
+            int actualCount = 0;
+            boolean deductTimeout = false;
+            int timeout = 1000;
+            for(int i = 1; i <= _count; i++, actualCount++)
+            {
+                TextMessage message = (TextMessage)messageConsumer.receive(timeout);
+                if(message == null)
+                {
+                    System.out.println("Message not received, stopping");
+                    deductTimeout = true;
+                    break;
+                }
+                if(i % 100 == 0)
+                {
+                    System.out.println("Got message " + i + ":" + message.getText());
+                }
+            }
+
+            long finish = System.currentTimeMillis();
+            long taken = finish - start;
+            if(deductTimeout)
+            {
+                taken -= timeout;
+            }
+            System.out.println("Received " + actualCount +" messages in " + taken + "ms");
+
+            connection.close();
+        }
+        catch (Exception exp)
+        {
+            exp.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    public static void main(String[] argv) throws Exception
+    {
+        List<String> switches = new ArrayList<String>();
+        List<String> args = new ArrayList<String>();
+        for (String s : argv)
+        {
+            if (s.startsWith("-"))
+            {
+                switches.add(s);
+            }
+            else
+            {
+                args.add(s);
+            }
+        }
+
+        int count = args.isEmpty() ? DEFAULT_COUNT : Integer.parseInt(args.remove(0));
+        String hostname = args.isEmpty() ? DEFAULT_HOST : args.remove(0);
+        int port = args.isEmpty() ? DEFAULT_PORT : Integer.parseInt(args.remove(0));
+        String queuePrefix = args.isEmpty() ? null : args.remove(0);
+
+        new Drain(count, hostname, port, queuePrefix).runExample();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Spout.java
----------------------------------------------------------------------
diff --git a/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Spout.java b/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Spout.java
new file mode 100644
index 0000000..f6b15e7
--- /dev/null
+++ b/qpid-jms-examples/src/main/java/org/apache/qpid/jms/example/Spout.java
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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.jms.example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+
+public class Spout
+{
+    private static final String DEFAULT_USER = "guest";
+    private static final String DEFAULT_PASSWORD = "guest";
+    private static final int DEFAULT_PORT = 5672;
+    private static final String DEFAULT_HOST = "localhost";
+    private static final int DEFAULT_COUNT = 10000;
+
+    private String _hostname;
+    private int _port;
+    private int _count;
+    private String _username;
+    private String _password;
+    private String _queuePrefix;
+    private boolean _persistent;
+
+    public Spout(int count, String hostname, int port, String queuePrefix, boolean persistent)
+    {
+        _count = count;
+        _hostname = hostname;
+        _port = port;
+        _persistent = persistent;
+        _username = DEFAULT_USER;
+        _password = DEFAULT_PASSWORD;
+        _queuePrefix = queuePrefix;
+    }
+
+    public void runExample()
+    {
+        try
+        {
+            //TODO: use JNDI lookup rather than direct instantiation
+            JmsConnectionFactory factory = new JmsConnectionFactory("amqp://" + _hostname + ":" + _port);
+            if(_queuePrefix != null)
+            {
+                //TODO: use URL options?
+                factory.setQueuePrefix(_queuePrefix);
+            }
+
+            Connection connection = factory.createConnection(_username,_password);
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+            Destination queue = session.createQueue("myQueue");
+            MessageProducer messageProducer = session.createProducer(queue);
+
+            int dekiveryMode = _persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT;
+
+            long start = System.currentTimeMillis();
+            for(int i = 1; i <= _count; i++)
+            {
+                TextMessage message = session.createTextMessage("Hello world!");
+                messageProducer.send(message, dekiveryMode, Message.DEFAULT_PRIORITY, Message.DEFAULT_TIME_TO_LIVE);
+
+                if(i % 100 == 0)
+                {
+                    System.out.println("Sent message " + i + ":" + message.getText());
+                }
+            }
+
+            long finish = System.currentTimeMillis();
+            long taken = finish - start;
+            System.out.println("Sent " + _count +" messages in " + taken + "ms");
+
+            connection.close();
+        }
+        catch (Exception exp)
+        {
+            exp.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    public static void main(String[] argv) throws Exception
+    {
+        List<String> switches = new ArrayList<String>();
+        List<String> args = new ArrayList<String>();
+        for (String s : argv)
+        {
+            if (s.startsWith("-"))
+            {
+                switches.add(s);
+            }
+            else
+            {
+                args.add(s);
+            }
+        }
+
+        int count = args.isEmpty() ? DEFAULT_COUNT : Integer.parseInt(args.remove(0));
+        String hostname = args.isEmpty() ? DEFAULT_HOST : args.remove(0);
+        int port = args.isEmpty() ? DEFAULT_PORT : Integer.parseInt(args.remove(0));
+        String queuePrefix = args.isEmpty() ? null : args.remove(0);
+        boolean persistent = switches.contains("-p");
+
+        new Spout(count, hostname, port, queuePrefix, persistent).runExample();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/.gitignore
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/.gitignore b/qpid-jms-interop-tests/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/qpid-jms-interop-tests/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/README.md
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/README.md b/qpid-jms-interop-tests/README.md
new file mode 100644
index 0000000..ba1bae9
--- /dev/null
+++ b/qpid-jms-interop-tests/README.md
@@ -0,0 +1,3 @@
+AMQP JMS Client Broker Interop tests
+----------------------------------------------
+This module contains maven submodules that should exercise the JMS client against different AMQP message brokers in order to ensure that it can work with as many AMQP brokers as possible.

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/pom.xml b/qpid-jms-interop-tests/pom.xml
new file mode 100644
index 0000000..30a9101
--- /dev/null
+++ b/qpid-jms-interop-tests/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>qpid-jms-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>qpid-jms-interop-tests</artifactId>
+  <name>QpidJMS Broker Interop Tests</name>
+  <description>A set of modules meant for testing interoperability between the client and various AMQP Brokers.</description>
+  <packaging>pom</packaging>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <modules>
+    <module>qpid-jms-activemq-tests</module>
+  </modules>
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/.gitignore
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/.gitignore b/qpid-jms-interop-tests/qpid-jms-activemq-tests/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/pom.xml b/qpid-jms-interop-tests/qpid-jms-activemq-tests/pom.xml
new file mode 100644
index 0000000..0087cd0
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/pom.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>qpid-jms-interop-tests</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>qpid-jms-activemq-tests</artifactId>
+  <name>QpidJMS ActiveMQ Interop Tests</name>
+  <description>Tests the JMS client against the ActiveMQ Broker.</description>
+  <packaging>jar</packaging>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <!-- =================================== -->
+    <!-- Required Dependencies                -->
+    <!-- =================================== -->
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-jms-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-jms-discovery</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>apollo-selector</artifactId>
+      <optional>true</optional>
+    </dependency>
+
+    <!-- =================================== -->
+    <!-- Testing Dependencies                -->
+    <!-- =================================== -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <!--  Joram JMS conformance tests -->
+    <dependency>
+      <groupId>org.fusesource.joram-jms-tests</groupId>
+      <artifactId>joram-jms-tests</artifactId>
+      <version>${fuse-joram-tests-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <!-- using it for Jetty's JNDI context to work /w Joram tests. -->
+      <groupId>org.eclipse.jetty.aggregate</groupId>
+      <artifactId>jetty-all-server</artifactId>
+      <version>${jetty-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-broker</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-kahadb-store</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-amqp</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-jaas</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-spring</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionCloseVariationsTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionCloseVariationsTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionCloseVariationsTest.java
new file mode 100644
index 0000000..32bd170
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionCloseVariationsTest.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.jms;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * A test case for Connection close called under different circumstances.
+ */
+public class JmsConnectionCloseVariationsTest extends AmqpTestSupport {
+
+    @Test(timeout=60000)
+    public void testCloseAfterBrokerStopped() throws Exception {
+        doTestConnectionClosedAfterBrokerStopped();
+    }
+
+    @Test(timeout=90000)
+    public void testCloseAfterBrokerStoppedRepeated() throws Exception {
+        for (int i = 0; i < 50; ++i) {
+            doTestConnectionClosedAfterBrokerStopped();
+            restartPrimaryBroker();
+        }
+    }
+
+    private void doTestConnectionClosedAfterBrokerStopped() throws Exception {
+        Connection connection = createAmqpConnection();
+        connection.start();
+        stopPrimaryBroker();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testCloseBeforeBrokerStopped() throws Exception {
+        doTestConnectionClosedBeforeBrokerStopped();
+    }
+
+    @Test(timeout=90000)
+    public void testCloseBeforeBrokerStoppedRepeated() throws Exception {
+        for (int i = 0; i < 50; ++i) {
+            doTestConnectionClosedBeforeBrokerStopped();
+            restartPrimaryBroker();
+        }
+    }
+
+    private void doTestConnectionClosedBeforeBrokerStopped() throws Exception {
+        Connection connection = createAmqpConnection();
+        connection.start();
+        connection.close();
+        stopPrimaryBroker();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionClosedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionClosedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionClosedTest.java
new file mode 100644
index 0000000..773deeb
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionClosedTest.java
@@ -0,0 +1,103 @@
+/**
+ * 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.jms;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test Connection methods contracts when state is closed.
+ */
+public class JmsConnectionClosedTest extends AmqpTestSupport {
+
+    protected Destination destination;
+
+    protected Connection createConnection() throws Exception {
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        destination = session.createTopic("test");
+        connection.close();
+        return connection;
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        createConnection();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetClientIdFails() throws JMSException {
+        connection.getClientID();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetClientIdFails() throws JMSException {
+        connection.setClientID("test");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetMetaData() throws JMSException {
+        connection.getMetaData();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetExceptionListener() throws JMSException {
+        connection.getExceptionListener();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetExceptionListener() throws JMSException {
+        connection.setExceptionListener(new ExceptionListener() {
+            @Override
+            public void onException(JMSException exception) {
+            }
+        });
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testStartFails() throws JMSException {
+        connection.start();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testStopFails() throws JMSException {
+        connection.stop();
+    }
+
+    @Test(timeout=30000)
+    public void testClose() throws JMSException {
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateConnectionConsumerFails() throws JMSException {
+        connection.createConnectionConsumer(destination, "", null, 1);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateDurableConnectionConsumerFails() throws JMSException {
+        connection.createDurableConnectionConsumer((Topic) destination, "id", "", null, 1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionConcurrentCloseCallsTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionConcurrentCloseCallsTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionConcurrentCloseCallsTest.java
new file mode 100644
index 0000000..4bf4f73
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionConcurrentCloseCallsTest.java
@@ -0,0 +1,95 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+public class JmsConnectionConcurrentCloseCallsTest extends AmqpTestSupport {
+
+    private JmsConnection connection;
+    private ExecutorService executor;
+    private final int size = 200;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        executor = Executors.newFixedThreadPool(20);
+        connection = (JmsConnection) createAmqpConnection();
+        connection.start();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        if (connection.isStarted()) {
+            connection.stop();
+        }
+        if (executor != null) {
+            executor.shutdownNow();
+        }
+
+        super.tearDown();
+    }
+
+    @Test(timeout=200000)
+    public void testCloseMultipleTimes() throws Exception {
+        connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+        assertTrue(connection.isStarted());
+        assertFalse(connection.isClosed());
+
+        final CountDownLatch latch = new CountDownLatch(size);
+
+        for (int i = 0; i < size; i++) {
+            executor.submit(new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+                        connection.close();
+                        assertFalse(connection.isStarted());
+                        assertTrue(connection.isClosed());
+                        latch.countDown();
+                    } catch (Throwable e) {
+                        LOG.warn("Caught an exception: {}", e);
+                    }
+                }
+            });
+        }
+
+        boolean zero = latch.await(200, TimeUnit.SECONDS);
+        assertTrue("Should complete all", zero);
+
+        // should not fail calling again
+        connection.close();
+
+        assertFalse(connection.isStarted());
+        assertTrue(connection.isClosed());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
new file mode 100644
index 0000000..b1dc4da
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFactoryTest.java
@@ -0,0 +1,118 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+public class JmsConnectionFactoryTest extends AmqpTestSupport {
+
+    private final String username = "USER";
+    private final String password = "PASSWORD";
+
+    protected String getGoodProviderAddress() {
+        return getBrokerAmqpConnectionURI().toString();
+    }
+
+    protected URI getGoodProviderAddressURI() throws URISyntaxException {
+        return new URI(getGoodProviderAddress());
+    }
+
+    protected String getBadProviderAddress() {
+        return "bad://127.0.0.1:" + 5763;
+    }
+
+    protected URI getBadProviderAddressURI() throws URISyntaxException {
+        return new URI(getBadProviderAddress());
+    }
+
+    @Test(timeout=60000)
+    public void testConnectionFactoryCreate() {
+        JmsConnectionFactory factory = new JmsConnectionFactory();
+        assertNull(factory.getUsername());
+        assertNull(factory.getPassword());
+    }
+
+    @Test(timeout=60000)
+    public void testConnectionFactoryCreateUsernameAndPassword() {
+        JmsConnectionFactory factory = new JmsConnectionFactory(username, password);
+        assertNotNull(factory.getUsername());
+        assertNotNull(factory.getPassword());
+        assertEquals(username, factory.getUsername());
+        assertEquals(password, factory.getPassword());
+    }
+
+    @Test(expected = JMSException.class)
+    public void testCreateConnectionBadProviderURI() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBadProviderAddressURI());
+        factory.createConnection();
+    }
+
+    @Test(expected = JMSException.class)
+    public void testCreateConnectionBadProviderString() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBadProviderAddress());
+        factory.createConnection();
+    }
+
+    @Test(timeout=60000)
+    public void testCreateConnectionGoodProviderURI() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getGoodProviderAddressURI());
+        Connection connection = factory.createConnection();
+        assertNotNull(connection);
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testCreateConnectionGoodProviderString() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getGoodProviderAddress());
+        Connection connection = factory.createConnection();
+        assertNotNull(connection);
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testUriOptionsApplied() throws Exception {
+        String uri = getGoodProviderAddress() + "?jms.omitHost=true&jms.forceAsyncSend=true";
+        JmsConnectionFactory factory = new JmsConnectionFactory(uri);
+        assertTrue(factory.isOmitHost());
+        assertTrue(factory.isForceAsyncSend());
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        assertTrue(connection.isOmitHost());
+        assertTrue(connection.isForceAsyncSend());
+        connection.close();
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testBadUriOptionCausesFail() throws Exception {
+        String uri = getGoodProviderAddress() + "?jms.omitHost=true&jms.badOption=true";
+        new JmsConnectionFactory(uri);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFailedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFailedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFailedTest.java
new file mode 100644
index 0000000..b14792e
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionFailedTest.java
@@ -0,0 +1,60 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.Wait;
+
+/**
+ * Test Connection methods contracts when connection has failed.
+ */
+public class JmsConnectionFailedTest extends JmsConnectionClosedTest {
+
+    @Override
+    protected Connection createConnection() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        connection = createAmqpConnection();
+        connection.setExceptionListener(new ExceptionListener() {
+
+            @Override
+            public void onException(JMSException exception) {
+                latch.countDown();
+            }
+        });
+        connection.start();
+        stopPrimaryBroker();
+        assertTrue(latch.await(20, TimeUnit.SECONDS));
+        final JmsConnection jmsConnection = (JmsConnection) connection;
+        assertTrue(Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return !jmsConnection.isConnected();
+            }
+        }));
+        return connection;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionTest.java
new file mode 100644
index 0000000..d328dab
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsConnectionTest.java
@@ -0,0 +1,144 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test for basic JmsConnection functionality and error handling.
+ */
+public class JmsConnectionTest extends AmqpTestSupport {
+
+    @Test(timeout=30000)
+    public void testCreateConnection() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionAndStart() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(expected = JMSException.class)
+    public void testCreateWithDuplicateClientIdFails() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        JmsConnection connection1 = (JmsConnection) factory.createConnection();
+        connection1.setClientID("Test");
+        assertNotNull(connection1);
+        connection1.start();
+        JmsConnection connection2 = (JmsConnection) factory.createConnection();
+        connection2.setClientID("Test");
+        connection2.start();
+
+        connection1.close();
+        connection2.close();
+    }
+
+    @Test(expected = JMSException.class)
+    public void testSetClientIdAfterStartedFails() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        connection.setClientID("Test");
+        connection.start();
+        connection.setClientID("NewTest");
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionAsSystemAdmin() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        factory.setUsername("system");
+        factory.setPassword("manager");
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionCallSystemAdmin() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection("system", "manager");
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected = JMSSecurityException.class)
+    public void testCreateConnectionAsUnknwonUser() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        factory.setUsername("unknown");
+        factory.setPassword("unknown");
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected = JMSSecurityException.class)
+    public void testCreateConnectionCallUnknwonUser() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection("unknown", "unknown");
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testConnectionExceptionBrokerStop() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        Connection connection = createAmqpConnection();
+        connection.setExceptionListener(new ExceptionListener() {
+
+            @Override
+            public void onException(JMSException exception) {
+                latch.countDown();
+            }
+        });
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+
+        stopPrimaryBroker();
+
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+
+        connection.close();
+    }
+}


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


[24/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
new file mode 100644
index 0000000..a7ede86
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSession.java
@@ -0,0 +1,1002 @@
+/**
+ * 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.jms;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.jms.BytesMessage;
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.InvalidSelectorException;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+import javax.jms.TopicSubscriber;
+
+import org.apache.activemq.apollo.filter.FilterException;
+import org.apache.activemq.apollo.selector.SelectorParser;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsMessageTransformation;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsMessageId;
+import org.apache.qpid.jms.meta.JmsProducerId;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFuture;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+
+/**
+ * JMS Session implementation
+ */
+@SuppressWarnings("static-access")
+public class JmsSession implements Session, QueueSession, TopicSession, JmsMessageDispatcher {
+
+    private final JmsConnection connection;
+    private final int acknowledgementMode;
+    private final List<JmsMessageProducer> producers = new CopyOnWriteArrayList<JmsMessageProducer>();
+    private final Map<JmsConsumerId, JmsMessageConsumer> consumers = new ConcurrentHashMap<JmsConsumerId, JmsMessageConsumer>();
+    private MessageListener messageListener;
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private final AtomicBoolean started = new AtomicBoolean();
+    private final LinkedBlockingQueue<JmsInboundMessageDispatch> stoppedMessages =
+        new LinkedBlockingQueue<JmsInboundMessageDispatch>(10000);
+    private JmsPrefetchPolicy prefetchPolicy;
+    private JmsSessionInfo sessionInfo;
+    private ExecutorService executor;
+    private final ReentrantLock sendLock = new ReentrantLock();
+
+    private final AtomicLong consumerIdGenerator = new AtomicLong();
+    private final AtomicLong producerIdGenerator = new AtomicLong();
+    private JmsLocalTransactionContext transactionContext;
+    private JmsMessageFactory messageFactory;
+
+    protected JmsSession(JmsConnection connection, JmsSessionId sessionId, int acknowledgementMode) throws JMSException {
+        this.connection = connection;
+        this.acknowledgementMode = acknowledgementMode;
+        this.prefetchPolicy = new JmsPrefetchPolicy(connection.getPrefetchPolicy());
+
+        setTransactionContext(new JmsLocalTransactionContext(this));
+
+        this.sessionInfo = new JmsSessionInfo(sessionId);
+        this.sessionInfo.setAcknowledgementMode(acknowledgementMode);
+        this.sessionInfo.setSendAcksAsync(connection.isSendAcksAsync());
+
+        this.sessionInfo = connection.createResource(sessionInfo);
+        this.messageFactory = connection.getMessageFactory();
+    }
+
+    int acknowledgementMode() {
+        return this.acknowledgementMode;
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Session methods
+    //////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public int getAcknowledgeMode() throws JMSException {
+        checkClosed();
+        return this.acknowledgementMode;
+    }
+
+    @Override
+    public boolean getTransacted() throws JMSException {
+        checkClosed();
+        return isTransacted();
+    }
+
+    @Override
+    public MessageListener getMessageListener() throws JMSException {
+        checkClosed();
+        return this.messageListener;
+    }
+
+    @Override
+    public void setMessageListener(MessageListener listener) throws JMSException {
+        checkClosed();
+        this.messageListener = listener;
+    }
+
+    @Override
+    public void recover() throws JMSException {
+        checkClosed();
+        if (getTransacted()) {
+            throw new javax.jms.IllegalStateException("Cannot call recover() on a transacted session");
+        }
+
+        this.connection.recover(getSessionId());
+    }
+
+    @Override
+    public void commit() throws JMSException {
+        checkClosed();
+
+        if (!getTransacted()) {
+           throw new javax.jms.IllegalStateException("Not a transacted session");
+        }
+
+        this.transactionContext.commit();
+    }
+
+    @Override
+    public void rollback() throws JMSException {
+        checkClosed();
+        if (!getTransacted()) {
+            throw new javax.jms.IllegalStateException("Not a transacted session");
+        }
+
+        this.transactionContext.rollback();
+
+        getExecutor().execute(new Runnable() {
+            @Override
+            public void run() {
+                for (JmsMessageConsumer c : consumers.values()) {
+                    c.drainMessageQueueToListener();
+                }
+            }
+        });
+    }
+
+    @Override
+    public void run() {
+        try {
+            checkClosed();
+        } catch (IllegalStateException e) {
+            throw new RuntimeException(e);
+        }
+
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void close() throws JMSException {
+        if (!closed.get()) {
+            doClose();
+        }
+    }
+
+    /**
+     * Shutdown the Session and release all resources.  Once completed the Session can
+     * request that the Provider destroy the Session and it's child resources.
+     *
+     * @throws JMSException
+     */
+    protected void doClose() throws JMSException {
+        boolean interrupted = Thread.interrupted();
+        shutdown();
+        this.connection.removeSession(this);
+        this.connection.destroyResource(sessionInfo);
+        if (interrupted) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    /**
+     * This method should terminate all Session resources and prepare for disposal of the
+     * Session.  It is called either from the Session close method or from the Connection
+     * when a close request is made and the Connection wants to cleanup all Session resources.
+     *
+     * This method should not attempt to send a destroy request to the Provider as that
+     * will either be done by another session method or is not needed when done by the parent
+     * Connection.
+     *
+     * @throws JMSException
+     */
+    protected void shutdown() throws JMSException {
+        if (closed.compareAndSet(false, true)) {
+            stop();
+            for (JmsMessageConsumer consumer : new ArrayList<JmsMessageConsumer>(this.consumers.values())) {
+                consumer.shutdown();
+            }
+
+            for (JmsMessageProducer producer : this.producers) {
+                producer.shutdown();
+            }
+
+            try {
+                if (getTransactionContext().isInTransaction()) {
+                    rollback();
+                }
+            } catch (JMSException e) {
+            }
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Consumer creation
+    //////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @param destination
+     * @return a MessageConsumer
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination) throws JMSException {
+        return createConsumer(destination, null);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @return MessageConsumer
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination,
+     *      java.lang.String)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException {
+        return createConsumer(destination, messageSelector, false);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @param NoLocal
+     * @return the MessageConsumer
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination,
+     *      java.lang.String, boolean)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean NoLocal) throws JMSException {
+        checkClosed();
+        checkDestination(destination);
+        messageSelector = checkSelector(messageSelector);
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, destination);
+        JmsTopicSubscriber result = new JmsTopicSubscriber(getNextConsumerId(), this, dest, NoLocal, messageSelector);
+        result.init();
+        return result;
+    }
+
+    /**
+     * @param queue
+     * @return QueueRecevier
+     * @throws JMSException
+     * @see javax.jms.QueueSession#createReceiver(javax.jms.Queue)
+     */
+    @Override
+    public QueueReceiver createReceiver(Queue queue) throws JMSException {
+        checkClosed();
+        checkDestination(queue);
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, queue);
+        JmsQueueReceiver result = new JmsQueueReceiver(getNextConsumerId(), this, dest, "");
+        result.init();
+        return result;
+    }
+
+    /**
+     * @param queue
+     * @param messageSelector
+     * @return QueueReceiver
+     * @throws JMSException
+     * @see javax.jms.QueueSession#createReceiver(javax.jms.Queue,
+     *      java.lang.String)
+     */
+    @Override
+    public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException {
+        checkClosed();
+        checkDestination(queue);
+        messageSelector = checkSelector(messageSelector);
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, queue);
+        JmsQueueReceiver result = new JmsQueueReceiver(getNextConsumerId(), this, dest, messageSelector);
+        result.init();
+        return result;
+    }
+
+    /**
+     * @param destination
+     * @return QueueBrowser
+     * @throws JMSException
+     * @see javax.jms.Session#createBrowser(javax.jms.Queue)
+     */
+    @Override
+    public QueueBrowser createBrowser(Queue destination) throws JMSException {
+        return createBrowser(destination, null);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @return QueueBrowser
+     * @throws JMSException
+     * @see javax.jms.Session#createBrowser(javax.jms.Queue, java.lang.String)
+     */
+    @Override
+    public QueueBrowser createBrowser(Queue destination, String messageSelector) throws JMSException {
+        checkClosed();
+        checkDestination(destination);
+        messageSelector = checkSelector(messageSelector);
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, destination);
+        JmsQueueBrowser result = new JmsQueueBrowser(this, dest, messageSelector);
+        return result;
+    }
+
+    /**
+     * @param topic
+     * @return TopicSubscriber
+     * @throws JMSException
+     * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic)
+     */
+    @Override
+    public TopicSubscriber createSubscriber(Topic topic) throws JMSException {
+        return createSubscriber(topic, null, false);
+    }
+
+    /**
+     * @param topic
+     * @param messageSelector
+     * @param noLocal
+     * @return TopicSubscriber
+     * @throws JMSException
+     * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic,
+     *      java.lang.String, boolean)
+     */
+    @Override
+    public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException {
+        checkClosed();
+        checkDestination(topic);
+        messageSelector = checkSelector(messageSelector);
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, topic);
+        JmsTopicSubscriber result = new JmsTopicSubscriber(getNextConsumerId(), this, dest, noLocal, messageSelector);
+        result.init();
+        return result;
+    }
+
+    /**
+     * @param topic
+     * @param name
+     * @return a TopicSubscriber
+     * @throws JMSException
+     * @see javax.jms.Session#createDurableSubscriber(javax.jms.Topic,
+     *      java.lang.String)
+     */
+    @Override
+    public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException {
+        return createDurableSubscriber(topic, name, null, false);
+    }
+
+    /**
+     * @param topic
+     * @param name
+     * @param messageSelector
+     * @param noLocal
+     * @return TopicSubscriber
+     * @throws JMSException
+     * @see javax.jms.Session#createDurableSubscriber(javax.jms.Topic,
+     *      java.lang.String, java.lang.String, boolean)
+     */
+    @Override
+    public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws JMSException {
+        checkClosed();
+        checkDestination(topic);
+        messageSelector = checkSelector(messageSelector);
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, topic);
+        JmsTopicSubscriber result = new JmsDurableTopicSubscriber(getNextConsumerId(), this, dest, name, false, messageSelector);
+        result.init();
+        return result;
+    }
+
+    /**
+     * @param name
+     * @throws JMSException
+     * @see javax.jms.Session#unsubscribe(java.lang.String)
+     */
+    @Override
+    public void unsubscribe(String name) throws JMSException {
+        checkClosed();
+        this.connection.unsubscribe(name);
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Producer creation
+    //////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @param destination
+     * @return MessageProducer
+     * @throws JMSException
+     * @see javax.jms.Session#createProducer(javax.jms.Destination)
+     */
+    @Override
+    public MessageProducer createProducer(Destination destination) throws JMSException {
+        checkClosed();
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, destination);
+        JmsMessageProducer result = new JmsMessageProducer(getNextProducerId(), this, dest);
+        add(result);
+        return result;
+    }
+
+    /**
+     * @param queue
+     * @return QueueSender
+     * @throws JMSException
+     * @see javax.jms.QueueSession#createSender(javax.jms.Queue)
+     */
+    @Override
+    public QueueSender createSender(Queue queue) throws JMSException {
+        checkClosed();
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, queue);
+        JmsQueueSender result = new JmsQueueSender(getNextProducerId(), this, dest);
+        return result;
+    }
+
+    /**
+     * @param topic
+     * @return TopicPublisher
+     * @throws JMSException
+     * @see javax.jms.TopicSession#createPublisher(javax.jms.Topic)
+     */
+    @Override
+    public TopicPublisher createPublisher(Topic topic) throws JMSException {
+        checkClosed();
+        JmsDestination dest = JmsMessageTransformation.transformDestination(connection, topic);
+        JmsTopicPublisher result = new JmsTopicPublisher(getNextProducerId(), this, dest);
+        add(result);
+        return result;
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Message creation
+    //////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public BytesMessage createBytesMessage() throws JMSException {
+        checkClosed();
+        return init(messageFactory.createBytesMessage());
+    }
+
+    @Override
+    public MapMessage createMapMessage() throws JMSException {
+        checkClosed();
+        return init(messageFactory.createMapMessage());
+    }
+
+    @Override
+    public Message createMessage() throws JMSException {
+        checkClosed();
+        return init(messageFactory.createMessage());
+    }
+
+    @Override
+    public ObjectMessage createObjectMessage() throws JMSException {
+        checkClosed();
+        return init(messageFactory.createObjectMessage(null));
+    }
+
+    @Override
+    public ObjectMessage createObjectMessage(Serializable object) throws JMSException {
+        checkClosed();
+        return init(messageFactory.createObjectMessage(object));
+    }
+
+    @Override
+    public StreamMessage createStreamMessage() throws JMSException {
+        checkClosed();
+        return init(messageFactory.createStreamMessage());
+    }
+
+    @Override
+    public TextMessage createTextMessage() throws JMSException {
+        checkClosed();
+        return init(messageFactory.createTextMessage(null));
+    }
+
+    @Override
+    public TextMessage createTextMessage(String text) throws JMSException {
+        checkClosed();
+        return init(messageFactory.createTextMessage(text));
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Destination creation
+    //////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @param queueName
+     * @return Queue
+     * @throws JMSException
+     * @see javax.jms.Session#createQueue(java.lang.String)
+     */
+    @Override
+    public Queue createQueue(String queueName) throws JMSException {
+        checkClosed();
+        return new JmsQueue(queueName);
+    }
+
+    /**
+     * @param topicName
+     * @return Topic
+     * @throws JMSException
+     * @see javax.jms.Session#createTopic(java.lang.String)
+     */
+    @Override
+    public Topic createTopic(String topicName) throws JMSException {
+        checkClosed();
+        return new JmsTopic(topicName);
+    }
+
+    /**
+     * @return TemporaryQueue
+     * @throws JMSException
+     * @see javax.jms.Session#createTemporaryQueue()
+     */
+    @Override
+    public TemporaryQueue createTemporaryQueue() throws JMSException {
+        checkClosed();
+        return connection.createTemporaryQueue();
+    }
+
+    /**
+     * @return TemporaryTopic
+     * @throws JMSException
+     * @see javax.jms.Session#createTemporaryTopic()
+     */
+    @Override
+    public TemporaryTopic createTemporaryTopic() throws JMSException {
+        checkClosed();
+        return connection.createTemporaryTopic();
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Session Implementation methods
+    //////////////////////////////////////////////////////////////////////////
+
+    protected void add(JmsMessageConsumer consumer) throws JMSException {
+        this.consumers.put(consumer.getConsumerId(), consumer);
+        this.connection.addDispatcher(consumer.getConsumerId(), this);
+
+        if (started.get()) {
+            consumer.start();
+        }
+    }
+
+    protected void remove(JmsMessageConsumer consumer) throws JMSException {
+        this.connection.removeDispatcher(consumer.getConsumerId());
+        this.consumers.remove(consumer.getConsumerId());
+    }
+
+    protected void add(JmsMessageProducer producer) {
+        this.producers.add(producer);
+    }
+
+    protected void remove(MessageProducer producer) {
+        this.producers.remove(producer);
+    }
+
+    protected void onException(Exception ex) {
+        this.connection.onException(ex);
+    }
+
+    protected void onException(JMSException ex) {
+        this.connection.onException(ex);
+    }
+
+    protected void send(JmsMessageProducer producer, Destination dest, Message msg, int deliveryMode, int priority, long timeToLive, boolean disableMsgId, boolean disableTimestamp) throws JMSException {
+        JmsDestination destination = JmsMessageTransformation.transformDestination(connection, dest);
+        send(producer, destination, msg, deliveryMode, priority, timeToLive, disableMsgId, disableTimestamp);
+    }
+
+    private void send(JmsMessageProducer producer, JmsDestination destination, Message original, int deliveryMode, int priority, long timeToLive, boolean disableMsgId, boolean disableTimestamp) throws JMSException {
+        sendLock.lock();
+        try {
+            startNextTransaction();
+
+            original.setJMSDeliveryMode(deliveryMode);
+            original.setJMSPriority(priority);
+            original.setJMSRedelivered(false);
+
+            long timeStamp = 0;
+            boolean hasTTL = timeToLive > 0;
+            if (!disableTimestamp || hasTTL) {
+                timeStamp = System.currentTimeMillis();
+            }
+
+            original.setJMSTimestamp(timeStamp);
+
+            if (hasTTL) {
+                original.setJMSExpiration(timeStamp + timeToLive);
+            }
+
+            JmsMessageId msgId = null;
+            if (!disableMsgId) {
+                msgId = getNextMessageId(producer);
+            }
+
+            boolean isJmsMessageType = original instanceof JmsMessage;
+            if (isJmsMessageType) {
+                ((JmsMessage) original).setConnection(connection);
+                if (!disableMsgId) {
+                    ((JmsMessage) original).setJMSMessageID(msgId);
+                }
+                original.setJMSDestination(destination);
+            }
+
+            JmsMessage copy = JmsMessageTransformation.transformMessage(connection, original);
+
+            // Ensure original message gets the destination and message ID as per spec.
+            if (!isJmsMessageType) {
+                if (!disableMsgId) {
+                    original.setJMSMessageID(msgId.toString());
+                    copy.setJMSMessageID(msgId);
+                }
+                original.setJMSDestination(destination);
+                copy.setJMSDestination(destination);
+            }
+
+            boolean sync = connection.isAlwaysSyncSend() ||
+                           (!connection.isForceAsyncSend() && deliveryMode == DeliveryMode.PERSISTENT && !getTransacted());
+
+            copy.onSend();
+            JmsOutboundMessageDispatch envelope = new JmsOutboundMessageDispatch();
+            envelope.setMessage(copy);
+            envelope.setProducerId(producer.getProducerId());
+            envelope.setDestination(destination);
+            envelope.setSendAsync(!sync);
+
+            this.connection.send(envelope);
+        } finally {
+            sendLock.unlock();
+        }
+    }
+
+    void acknowledge(JmsInboundMessageDispatch envelope, ACK_TYPE ackType) throws JMSException {
+        startNextTransaction();
+        this.connection.acknowledge(envelope, ackType);
+    }
+
+    /**
+     * Acknowledge all previously delivered messages in this Session as consumed.  This
+     * method is usually only called when the Session is in the CLIENT_ACKNOWLEDGE mode.
+     *
+     * @throws JMSException if an error occurs while the acknowledge is processed.
+     */
+    void acknowledge() throws JMSException {
+        this.connection.acknowledge(sessionInfo.getSessionId());
+    }
+
+    public boolean isClosed() {
+        return this.closed.get();
+    }
+
+    /**
+     * Checks whether the session uses transactions.
+     *
+     * @return true - if the session uses transactions.
+     */
+    public boolean isTransacted() {
+        return this.acknowledgementMode == Session.SESSION_TRANSACTED;
+    }
+
+    /**
+     * Checks whether the session used client acknowledgment.
+     *
+     * @return true - if the session uses client acknowledgment.
+     */
+    protected boolean isClientAcknowledge() {
+        return this.acknowledgementMode == Session.CLIENT_ACKNOWLEDGE;
+    }
+
+    /**
+     * Checks whether the session used auto acknowledgment.
+     *
+     * @return true - if the session uses client acknowledgment.
+     */
+    public boolean isAutoAcknowledge() {
+        return acknowledgementMode == Session.AUTO_ACKNOWLEDGE;
+    }
+
+    /**
+     * Checks whether the session used dup ok acknowledgment.
+     *
+     * @return true - if the session uses client acknowledgment.
+     */
+    public boolean isDupsOkAcknowledge() {
+        return acknowledgementMode == Session.DUPS_OK_ACKNOWLEDGE;
+    }
+
+    protected void checkClosed() throws IllegalStateException {
+        if (this.closed.get()) {
+            throw new IllegalStateException("The MessageProducer is closed");
+        }
+    }
+
+    // This extra wrapping class around SelectorParser is used to avoid
+    // ClassNotFoundException if SelectorParser is not in the class path.
+    static class OptionalSectorParser {
+        public static void check(String selector) throws InvalidSelectorException {
+            try {
+                SelectorParser.parse(selector);
+            } catch (FilterException e) {
+                throw new InvalidSelectorException(e.getMessage());
+            }
+        }
+    }
+
+    static final OptionalSectorParser SELECTOR_PARSER;
+    static {
+        OptionalSectorParser parser;
+        try {
+            // lets verify it's working..
+            parser = new OptionalSectorParser();
+            parser.check("x=1");
+        } catch (Throwable e) {
+            parser = null;
+        }
+        SELECTOR_PARSER = parser;
+    }
+
+    public static String checkSelector(String selector) throws InvalidSelectorException {
+        if (selector != null) {
+            if (selector.trim().length() == 0) {
+                return null;
+            }
+            if (SELECTOR_PARSER != null) {
+                SELECTOR_PARSER.check(selector);
+            }
+        }
+        return selector;
+    }
+
+    public static void checkDestination(Destination dest) throws InvalidDestinationException {
+        if (dest == null) {
+            throw new InvalidDestinationException("Destination cannot be null");
+        }
+    }
+
+    protected void start() throws JMSException {
+        if (started.compareAndSet(false, true)) {
+            JmsInboundMessageDispatch message = null;
+            while ((message = this.stoppedMessages.poll()) != null) {
+                deliver(message);
+            }
+            for (JmsMessageConsumer consumer : consumers.values()) {
+                consumer.start();
+            }
+        }
+    }
+
+    protected void stop() throws JMSException {
+        started.set(false);
+        if (executor != null) {
+            executor.shutdown();
+            executor = null;
+        }
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            consumer.stop();
+        }
+    }
+
+    protected boolean isStarted() {
+        return this.started.get();
+    }
+
+    public JmsConnection getConnection() {
+        return this.connection;
+    }
+
+    Executor getExecutor() {
+        if (executor == null) {
+            executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
+
+                @Override
+                public Thread newThread(Runnable runner) {
+                    Thread executor = new Thread(runner);
+                    executor.setName("JmsSession ["+ sessionInfo.getSessionId() + "] dispatcher");
+                    executor.setDaemon(true);
+                    return executor;
+                }
+            });
+        }
+        return executor;
+    }
+
+    protected JmsSessionInfo getSessionInfo() {
+        return this.sessionInfo;
+    }
+
+    protected JmsSessionId getSessionId() {
+        return this.sessionInfo.getSessionId();
+    }
+
+    protected JmsConsumerId getNextConsumerId() {
+        return new JmsConsumerId(sessionInfo.getSessionId(), consumerIdGenerator.incrementAndGet());
+    }
+
+    protected JmsProducerId getNextProducerId() {
+        return new JmsProducerId(sessionInfo.getSessionId(), producerIdGenerator.incrementAndGet());
+    }
+
+    private JmsMessageId getNextMessageId(JmsMessageProducer producer) {
+        return new JmsMessageId(producer.getProducerId(), producer.getNextMessageSequence());
+    }
+
+    private <T extends JmsMessage> T init(T message) {
+        message.setConnection(connection);
+        return message;
+    }
+
+    private synchronized void startNextTransaction() throws JMSException {
+        if (getTransacted()) {
+            transactionContext.begin();
+        }
+    }
+
+    boolean isDestinationInUse(JmsDestination destination) {
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            if (consumer.isUsingDestination(destination)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void checkMessageListener() throws JMSException {
+        if (messageListener != null) {
+            throw new IllegalStateException("Cannot synchronously receive a message when a MessageListener is set");
+        }
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            if (consumer.hasMessageListener()) {
+                throw new IllegalStateException("Cannot synchronously receive a message when a MessageListener is set");
+            }
+        }
+    }
+
+    public JmsPrefetchPolicy getPrefetchPolicy() {
+        return prefetchPolicy;
+    }
+
+    public void setPrefetchPolicy(JmsPrefetchPolicy prefetchPolicy) {
+        this.prefetchPolicy = prefetchPolicy;
+    }
+
+    @Override
+    public void onMessage(JmsInboundMessageDispatch envelope) {
+        if (started.get()) {
+            deliver(envelope);
+        } else {
+            this.stoppedMessages.add(envelope);
+        }
+    }
+
+    protected void onConnectionInterrupted() {
+        for (JmsMessageProducer producer : producers) {
+            producer.onConnectionInterrupted();
+        }
+
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            consumer.onConnectionInterrupted();
+        }
+    }
+
+    protected void onConnectionRecovery(Provider provider) throws Exception {
+
+        ProviderFuture request = new ProviderFuture();
+        provider.create(sessionInfo, request);
+        request.sync();
+
+        if (this.acknowledgementMode == SESSION_TRANSACTED) {
+            if (transactionContext.isInTransaction()) {
+                transactionContext.clear();
+                transactionContext.begin();
+            }
+        }
+
+        for (JmsMessageProducer producer : producers) {
+            producer.onConnectionRecovery(provider);
+        }
+
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            consumer.onConnectionRecovery(provider);
+        }
+    }
+
+    protected void onConnectionRecovered(Provider provider) throws Exception {
+
+        this.messageFactory = provider.getMessageFactory();
+
+        for (JmsMessageProducer producer : producers) {
+            producer.onConnectionRecovered(provider);
+        }
+
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            consumer.onConnectionRecovered(provider);
+        }
+    }
+
+    protected void onConnectionRestored() {
+        for (JmsMessageProducer producer : producers) {
+            producer.onConnectionRestored();
+        }
+
+        for (JmsMessageConsumer consumer : consumers.values()) {
+            consumer.onConnectionRestored();
+        }
+    }
+
+    private void deliver(JmsInboundMessageDispatch envelope) {
+        JmsConsumerId id = envelope.getConsumerId();
+        if (id == null) {
+            this.connection.onException(new JMSException("No ConsumerId set for " + envelope.getMessage()));
+        }
+        if (this.messageListener != null) {
+            this.messageListener.onMessage(envelope.getMessage());
+        } else {
+            JmsMessageConsumer consumer = this.consumers.get(id);
+            if (consumer != null) {
+                consumer.onMessage(envelope);
+            }
+        }
+    }
+
+    /**
+     * Sets the transaction context of the session.
+     *
+     * @param transactionContext
+     *        provides the means to control a JMS transaction.
+     */
+    public void setTransactionContext(JmsLocalTransactionContext transactionContext) {
+        this.transactionContext = transactionContext;
+    }
+
+    /**
+     * Returns the transaction context of the session.
+     *
+     * @return transactionContext
+     *         session's transaction context.
+     */
+    public JmsLocalTransactionContext getTransactionContext() {
+        return transactionContext;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslConnectionFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslConnectionFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslConnectionFactory.java
new file mode 100644
index 0000000..cefe491
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslConnectionFactory.java
@@ -0,0 +1,93 @@
+/**
+ * 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.jms;
+
+import java.net.URI;
+
+import org.apache.qpid.jms.provider.Provider;
+
+/**
+ * SSL Aware Factory class that allows for configuration of the SSL values used
+ * in the Provider transports that are SSL aware.
+ */
+public class JmsSslConnectionFactory extends JmsConnectionFactory {
+
+    private final JmsSslContext configured = JmsSslContext.getCurrentSslContext();
+
+    public JmsSslConnectionFactory() {
+    }
+
+    public JmsSslConnectionFactory(String username, String password) {
+        super(username, password);
+    }
+
+    public JmsSslConnectionFactory(String brokerURI) {
+        super(brokerURI);
+    }
+
+    public JmsSslConnectionFactory(URI brokerURI) {
+        super(brokerURI);
+    }
+
+    public JmsSslConnectionFactory(String username, String password, URI brokerURI) {
+        super(username, password, brokerURI);
+    }
+
+    public JmsSslConnectionFactory(String username, String password, String brokerURI) {
+        super(username, password, brokerURI);
+    }
+
+    @Override
+    protected Provider createProvider(URI brokerURI) throws Exception {
+        // Create and set a new instance as the current JmsSslContext for this thread
+        // based on current configuration settings.
+        JmsSslContext.setCurrentSslContext(configured.copy());
+        return super.createProvider(brokerURI);
+    }
+
+    public String getKeyStoreLocation() {
+        return configured.getKeyStoreLocation();
+    }
+
+    public void setKeyStoreLocation(String keyStoreLocation) {
+        this.configured.setKeyStoreLocation(keyStoreLocation);
+    }
+
+    public String getKeyStorePassword() {
+        return configured.getKeyStorePassword();
+    }
+
+    public void setKeyStorePassword(String keyStorePassword) {
+        this.configured.setKeyStorePassword(keyStorePassword);
+    }
+
+    public String getTrustStoreLocation() {
+        return configured.getTrustStoreLocation();
+    }
+
+    public void setTrustStoreLocation(String trustStoreLocation) {
+        this.configured.setTrustStoreLocation(trustStoreLocation);
+    }
+
+    public String getTrustStorePassword() {
+        return configured.getTrustStorePassword();
+    }
+
+    public void setTrustStorePassword(String trustStorePassword) {
+        this.configured.setTrustStorePassword(trustStorePassword);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslContext.java
new file mode 100644
index 0000000..feca77c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsSslContext.java
@@ -0,0 +1,100 @@
+/**
+ * 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.jms;
+
+/**
+ * Provides a wrapper around the SSL settings that are used by Provider transport
+ * instances that use an SSL encryption layer.
+ */
+public class JmsSslContext {
+
+    private String keyStoreLocation;
+    private String keyStorePassword;
+    private String trustStoreLocation;
+    private String trustStorePassword;
+
+    private static final JmsSslContext initial = new JmsSslContext();
+    private static final ThreadLocal<JmsSslContext> current;
+
+    static {
+
+        initial.setKeyStoreLocation(System.getProperty("javax.net.ssl.keyStore"));
+        initial.setKeyStorePassword(System.getProperty("javax.net.ssl.keyStorePassword"));
+        initial.setTrustStoreLocation(System.getProperty("javax.net.ssl.trustStore"));
+        initial.setTrustStorePassword(System.getProperty("javax.net.ssl.keyStorePassword"));
+
+        current = new ThreadLocal<JmsSslContext>() {
+
+            @Override
+            protected JmsSslContext initialValue() {
+                return initial;
+            }
+        };
+    }
+
+    protected JmsSslContext() {
+    }
+
+    public JmsSslContext copy() {
+        JmsSslContext result = new JmsSslContext();
+        result.setKeyStoreLocation(keyStoreLocation);
+        result.setKeyStorePassword(keyStorePassword);
+        result.setTrustStoreLocation(trustStoreLocation);
+        result.setTrustStorePassword(trustStorePassword);
+        return result;
+    }
+
+    static public void setCurrentSslContext(JmsSslContext bs) {
+        current.set(bs);
+    }
+
+    static public JmsSslContext getCurrentSslContext() {
+        return current.get();
+    }
+
+    public String getKeyStoreLocation() {
+        return keyStoreLocation;
+    }
+
+    public void setKeyStoreLocation(String keyStoreLocation) {
+        this.keyStoreLocation = keyStoreLocation;
+    }
+
+    public String getKeyStorePassword() {
+        return keyStorePassword;
+    }
+
+    public void setKeyStorePassword(String keyStorePassword) {
+        this.keyStorePassword = keyStorePassword;
+    }
+
+    public String getTrustStoreLocation() {
+        return trustStoreLocation;
+    }
+
+    public void setTrustStoreLocation(String trustStoreLocation) {
+        this.trustStoreLocation = trustStoreLocation;
+    }
+
+    public String getTrustStorePassword() {
+        return trustStorePassword;
+    }
+
+    public void setTrustStorePassword(String trustStorePassword) {
+        this.trustStorePassword = trustStorePassword;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryQueue.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryQueue.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryQueue.java
new file mode 100644
index 0000000..cff489b
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryQueue.java
@@ -0,0 +1,62 @@
+/**
+ * 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.jms;
+
+import javax.jms.JMSException;
+import javax.jms.TemporaryQueue;
+
+/**
+ * Temporary Queue Object
+ */
+public class JmsTemporaryQueue extends JmsDestination implements TemporaryQueue {
+
+    public JmsTemporaryQueue() {
+        this(null);
+    }
+
+    public JmsTemporaryQueue(String name) {
+        super(name, false, true);
+    }
+
+    @Override
+    public JmsTemporaryQueue copy() {
+        final JmsTemporaryQueue copy = new JmsTemporaryQueue();
+        copy.setProperties(getProperties());
+        return copy;
+    }
+
+    /**
+     * @see javax.jms.TemporaryQueue#delete()
+     */
+    @Override
+    public void delete() {
+        try {
+            tryDelete();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @return name
+     * @see javax.jms.Queue#getQueueName()
+     */
+    @Override
+    public String getQueueName() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryTopic.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryTopic.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryTopic.java
new file mode 100644
index 0000000..46dfed3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTemporaryTopic.java
@@ -0,0 +1,62 @@
+/**
+ * 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.jms;
+
+import javax.jms.JMSException;
+import javax.jms.TemporaryTopic;
+
+/**
+ * Temporary Topic Object
+ */
+public class JmsTemporaryTopic extends JmsDestination implements TemporaryTopic {
+
+    public JmsTemporaryTopic() {
+        super(null, true, true);
+    }
+
+    public JmsTemporaryTopic(String name) {
+        super(name, true, true);
+    }
+
+    @Override
+    public JmsTemporaryTopic copy() {
+        final JmsTemporaryTopic copy = new JmsTemporaryTopic();
+        copy.setProperties(getProperties());
+        return copy;
+    }
+
+    /**
+     * @see javax.jms.TemporaryTopic#delete()
+     */
+    @Override
+    public void delete() {
+        try {
+            tryDelete();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @return name
+     * @see javax.jms.Topic#getTopicName()
+     */
+    @Override
+    public String getTopicName() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopic.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopic.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopic.java
new file mode 100644
index 0000000..1840cc7
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopic.java
@@ -0,0 +1,49 @@
+/**
+ * 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.jms;
+
+import javax.jms.Topic;
+
+/**
+ * JMS Topic object.
+ */
+public class JmsTopic extends JmsDestination implements Topic {
+
+    public JmsTopic() {
+        this(null);
+    }
+
+    public JmsTopic(String name) {
+        super(name, true, false);
+    }
+
+    @Override
+    public JmsTopic copy() {
+        final JmsTopic copy = new JmsTopic();
+        copy.setProperties(getProperties());
+        return copy;
+    }
+
+    /**
+     * @return the name
+     * @see javax.jms.Topic#getTopicName()
+     */
+    @Override
+    public String getTopicName() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicConnection.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicConnection.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicConnection.java
new file mode 100644
index 0000000..c8fcaba
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicConnection.java
@@ -0,0 +1,43 @@
+/**
+ * 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.jms;
+
+import javax.jms.ConnectionConsumer;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueSession;
+import javax.jms.ServerSessionPool;
+
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.util.IdGenerator;
+
+public class JmsTopicConnection extends JmsConnection {
+
+    public JmsTopicConnection(String connectionId, Provider provider, IdGenerator clientIdGenerator) throws JMSException {
+        super(connectionId, provider, clientIdGenerator);
+    }
+
+    @Override
+    public ConnectionConsumer createConnectionConsumer(Queue queue, String messageSelector, ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        throw new javax.jms.IllegalStateException("Operation not supported by a TopicConnection");
+    }
+
+    @Override
+    public QueueSession createQueueSession(boolean transacted, int acknowledgeMode) throws JMSException {
+        throw new javax.jms.IllegalStateException("Operation not supported by a TopicConnection");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicPublisher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicPublisher.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicPublisher.java
new file mode 100644
index 0000000..47d5088
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicPublisher.java
@@ -0,0 +1,100 @@
+/**
+ * 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.jms;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+
+import org.apache.qpid.jms.meta.JmsProducerId;
+
+/**
+ * Implementation of a TopicPublisher
+ */
+public class JmsTopicPublisher extends JmsMessageProducer implements TopicPublisher {
+
+    /**
+     * Constructor
+     *
+     * @param s
+     * @param destination
+     */
+    protected JmsTopicPublisher(JmsProducerId id, JmsSession session, JmsDestination destination) throws JMSException {
+        super(id, session, destination);
+    }
+
+    /**
+     * @return the Topic
+     * @throws IllegalStateException
+     * @see javax.jms.TopicPublisher#getTopic()
+     */
+    @Override
+    public Topic getTopic() throws IllegalStateException {
+        checkClosed();
+        return (Topic) this.producerInfo.getDestination();
+    }
+
+    /**
+     * @param message
+     * @throws JMSException
+     * @see javax.jms.TopicPublisher#publish(javax.jms.Message)
+     */
+    @Override
+    public void publish(Message message) throws JMSException {
+        super.send(message);
+    }
+
+    /**
+     * @param topic
+     * @param message
+     * @throws JMSException
+     * @see javax.jms.TopicPublisher#publish(javax.jms.Topic, javax.jms.Message)
+     */
+    @Override
+    public void publish(Topic topic, Message message) throws JMSException {
+        super.send(topic, message);
+    }
+
+    /**
+     * @param message
+     * @param deliveryMode
+     * @param priority
+     * @param timeToLive
+     * @throws JMSException
+     * @see javax.jms.TopicPublisher#publish(javax.jms.Message, int, int, long)
+     */
+    @Override
+    public void publish(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+        super.send(message, deliveryMode, priority, timeToLive);
+    }
+
+    /**
+     * @param topic
+     * @param message
+     * @param deliveryMode
+     * @param priority
+     * @param timeToLive
+     * @throws JMSException
+     * @see javax.jms.TopicPublisher#publish(javax.jms.Topic, javax.jms.Message, int, int, long)
+     */
+    @Override
+    public void publish(Topic topic, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+        super.send(topic, message, deliveryMode, priority, timeToLive);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSession.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSession.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSession.java
new file mode 100644
index 0000000..ff834aa
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSession.java
@@ -0,0 +1,163 @@
+/**
+ * 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.jms;
+
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.QueueReceiver;
+import javax.jms.QueueSender;
+import javax.jms.TemporaryQueue;
+
+import org.apache.qpid.jms.meta.JmsSessionId;
+
+/**
+ * Implementation of a TopicSession
+ */
+public class JmsTopicSession extends JmsSession {
+
+    protected JmsTopicSession(JmsConnection connection, JmsSessionId sessionId, int acknowledgementMode) throws JMSException {
+        super(connection, sessionId, acknowledgementMode);
+    }
+
+    /**
+     * @param queue
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createBrowser(javax.jms.Queue)
+     */
+    @Override
+    public QueueBrowser createBrowser(Queue queue) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+
+    /**
+     * @param queue
+     * @param messageSelector
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createBrowser(javax.jms.Queue, java.lang.String)
+     */
+    @Override
+    public QueueBrowser createBrowser(Queue queue, String messageSelector) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+
+    /**
+     * @param destination
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination) throws JMSException {
+        if (destination instanceof Queue) {
+            throw new IllegalStateException("Operation not supported by a TopicSession");
+        }
+        return super.createConsumer(destination);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination,
+     *      java.lang.String)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException {
+        if (destination instanceof Queue) {
+            throw new IllegalStateException("Operation not supported by a TopicSession");
+        }
+        return super.createConsumer(destination, messageSelector);
+    }
+
+    /**
+     * @param destination
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createProducer(javax.jms.Destination)
+     */
+    @Override
+    public MessageProducer createProducer(Destination destination) throws JMSException {
+        if (destination instanceof Queue) {
+            throw new IllegalStateException("Operation not supported by a TopicSession");
+        }
+        return super.createProducer(destination);
+    }
+
+    /**
+     * @param queueName
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createQueue(java.lang.String)
+     */
+    @Override
+    public Queue createQueue(String queueName) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+
+    /**
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createTemporaryQueue()
+     */
+    @Override
+    public TemporaryQueue createTemporaryQueue() throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+
+    /**
+     * @param queue
+     * @return
+     * @throws JMSException
+     * @see javax.jms.QueueSession#createReceiver(javax.jms.Queue)
+     */
+    @Override
+    public QueueReceiver createReceiver(Queue queue) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+
+    /**
+     * @param queue
+     * @param messageSelector
+     * @return
+     * @throws JMSException
+     * @see javax.jms.QueueSession#createReceiver(javax.jms.Queue,
+     *      java.lang.String)
+     */
+    @Override
+    public QueueReceiver createReceiver(Queue queue, String messageSelector) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+
+    /**
+     * @param queue
+     * @return
+     * @throws JMSException
+     * @see javax.jms.QueueSession#createSender(javax.jms.Queue)
+     */
+    @Override
+    public QueueSender createSender(Queue queue) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a TopicSession");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSubscriber.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSubscriber.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSubscriber.java
new file mode 100644
index 0000000..0ef463a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTopicSubscriber.java
@@ -0,0 +1,70 @@
+/**
+ * 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.jms;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+import org.apache.qpid.jms.meta.JmsConsumerId;
+
+/**
+ * Implementation of a TopicSubscriber
+ */
+public class JmsTopicSubscriber extends JmsMessageConsumer implements TopicSubscriber {
+
+    /**
+     * Creates a non-durable TopicSubscriber
+     *
+     * @param id
+     * @param s
+     * @param destination
+     * @param noLocal
+     * @param selector
+     * @throws JMSException
+     */
+    JmsTopicSubscriber(JmsConsumerId id, JmsSession s, JmsDestination destination, boolean noLocal, String selector) throws JMSException {
+        super(id, s, destination, selector, noLocal);
+    }
+
+    /**
+     * Creates a TopicSubscriber that is durable.
+     *
+     * @param id
+     * @param s
+     * @param destination
+     * @param name
+     * @param noLocal
+     * @param selector
+     * @throws JMSException
+     */
+    JmsTopicSubscriber(JmsConsumerId id, JmsSession s, JmsDestination destination, String name, boolean noLocal, String selector) throws JMSException {
+        super(id, s, destination, name, selector, noLocal);
+    }
+
+    /**
+     * @return the Topic
+     * @throws IllegalStateException
+     * @see javax.jms.TopicSubscriber#getTopic()
+     */
+    @Override
+    public Topic getTopic() throws IllegalStateException {
+        checkClosed();
+        return (Topic) this.getDestination();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTransactionListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTransactionListener.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTransactionListener.java
new file mode 100644
index 0000000..c0704a1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTransactionListener.java
@@ -0,0 +1,31 @@
+/**
+ * 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.jms;
+
+/**
+ * Allows for a listener to be notified when a transaction is started, commits
+ * or is rolled back.
+ */
+public interface JmsTransactionListener {
+
+    void onTransactionStarted();
+
+    void onTransactionCommitted();
+
+    void onTransactionRolledBack();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTxSynchronization.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTxSynchronization.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTxSynchronization.java
new file mode 100644
index 0000000..bda7979
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsTxSynchronization.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms;
+
+/**
+ * Interface for JmsResources that are part of a running transaction to use
+ * to register for notifications of transaction commit and rollback in order
+ * to execute specific actions.
+ *
+ * One such use of this might be for a consumer to register a synchronization
+ * when it is closed while it's parent session is still operating inside a
+ * transaction.  The Consumer can close itself following the commit or rollback
+ * of the running Transaction.
+ */
+public abstract class JmsTxSynchronization {
+
+    /**
+     * Called after a successful commit of the current Transaction.
+     *
+     * @throws Exception
+     */
+    public void afterCommit() throws Exception {
+    }
+
+    /**
+     * Called after the current transaction has been rolled back either
+     * by a call to rollback or by a failure to complete a commit operation.
+     *
+     * @throws Exception
+     */
+    public void afterRollback() throws Exception {
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/IdConversionException.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/IdConversionException.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/IdConversionException.java
new file mode 100644
index 0000000..b04b988
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/IdConversionException.java
@@ -0,0 +1,36 @@
+/*
+ *
+ * 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.jms.exceptions;
+
+public class IdConversionException extends QpidJmsException
+{
+    private static final long serialVersionUID = -2349723813650476823L;
+
+    public IdConversionException(String reason)
+    {
+        super(reason);
+    }
+
+    public IdConversionException(String reason, Exception cause)
+    {
+        super(reason, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionClosedException.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionClosedException.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionClosedException.java
new file mode 100644
index 0000000..e58c54f
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionClosedException.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms.exceptions;
+
+import java.io.IOException;
+
+import javax.jms.IllegalStateException;
+
+/**
+ * An exception thrown when attempt is made to use a connection when the connection has been closed.
+ */
+public class JmsConnectionClosedException extends IllegalStateException {
+    private static final long serialVersionUID = -7975982446284065025L;
+
+
+    public JmsConnectionClosedException(IOException cause) {
+        super("The JMS connection has been closed: " + extractMessage(cause));
+        initCause(cause);
+        setLinkedException(cause);
+    }
+
+    public JmsConnectionClosedException() {
+        super("The JMS connection has been closed", "AlreadyClosed");
+    }
+
+    private static String extractMessage(IOException cause) {
+        String m = cause.getMessage();
+        if (m == null || m.length() == 0) {
+            m = cause.toString();
+        }
+        return m;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionFailedException.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionFailedException.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionFailedException.java
new file mode 100644
index 0000000..e9b7068
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsConnectionFailedException.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms.exceptions;
+
+import java.io.IOException;
+
+import javax.jms.IllegalStateException;
+
+/**
+ * An exception thrown when attempt is made to use a connection when the connection has already failed.
+ */
+public class JmsConnectionFailedException extends IllegalStateException {
+
+    private static final long serialVersionUID = -3386897790274799220L;
+
+    public JmsConnectionFailedException(IOException cause) {
+        super("The JMS connection has failed: " + extractMessage(cause));
+        initCause(cause);
+        setLinkedException(cause);
+    }
+
+    public JmsConnectionFailedException() {
+        super("The JMS connection has failed due to a Transport problem", "Connection Failed");
+    }
+
+    private static String extractMessage(IOException cause) {
+        String m = cause.getMessage();
+        if (m == null || m.length() == 0) {
+            m = cause.toString();
+        }
+        return m;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsExceptionSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsExceptionSupport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsExceptionSupport.java
new file mode 100644
index 0000000..81f9ca8
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/JmsExceptionSupport.java
@@ -0,0 +1,103 @@
+/**
+ * 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.jms.exceptions;
+
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+
+/**
+ * Exception support class.
+ *
+ * Factory class for creating JMSException instances based on String messages or by
+ * wrapping other non-JMS exception.
+ *
+ * @since 1.0
+ */
+public final class JmsExceptionSupport {
+
+    private JmsExceptionSupport() {}
+
+    public static JMSException create(String msg, Throwable cause) {
+        JMSException exception = new JMSException(msg);
+        exception.initCause(cause);
+        return exception;
+    }
+
+    public static JMSException create(String msg, Exception cause) {
+        JMSException exception = new JMSException(msg);
+        exception.setLinkedException(cause);
+        exception.initCause(cause);
+        return exception;
+    }
+
+    public static JMSException create(Throwable cause) {
+        if (cause instanceof JMSException) {
+            return (JMSException) cause;
+        }
+        if (cause.getCause() instanceof JMSException) {
+            return (JMSException) cause.getCause();
+        }
+
+        String msg = cause.getMessage();
+        if (msg == null || msg.length() == 0) {
+            msg = cause.toString();
+        }
+        JMSException exception = new JMSException(msg);
+        exception.initCause(cause);
+        return exception;
+    }
+
+    public static JMSException create(Exception cause) {
+        if (cause instanceof JMSException) {
+            return (JMSException) cause;
+        }
+        if (cause.getCause() instanceof JMSException) {
+            return (JMSException) cause.getCause();
+        }
+
+        String msg = cause.getMessage();
+        if (msg == null || msg.length() == 0) {
+            msg = cause.toString();
+        }
+        JMSException exception = new JMSException(msg);
+        exception.setLinkedException(cause);
+        exception.initCause(cause);
+        return exception;
+    }
+
+    public static MessageEOFException createMessageEOFException(Exception cause) {
+        String msg = cause.getMessage();
+        if (msg == null || msg.length() == 0) {
+            msg = cause.toString();
+        }
+        MessageEOFException exception = new MessageEOFException(msg);
+        exception.setLinkedException(cause);
+        exception.initCause(cause);
+        return exception;
+    }
+
+    public static MessageFormatException createMessageFormatException(Throwable cause) {
+        String msg = cause.getMessage();
+        if (msg == null || msg.length() == 0) {
+            msg = cause.toString();
+        }
+        MessageFormatException exception = new MessageFormatException(msg);
+        exception.initCause(cause);
+        return exception;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/QpidJmsException.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/QpidJmsException.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/QpidJmsException.java
new file mode 100644
index 0000000..a922530
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/exceptions/QpidJmsException.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * 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.jms.exceptions;
+
+import javax.jms.JMSException;
+
+public class QpidJmsException extends JMSException
+{
+    private static final long serialVersionUID = 751932967255393054L;
+
+    public QpidJmsException(String reason)
+    {
+        this(reason, null);
+    }
+
+    public QpidJmsException(String reason, Exception cause)
+    {
+        super(reason);
+        if (cause != null)
+        {
+            setLinkedException(cause);
+            initCause(cause);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIReferenceFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIReferenceFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIReferenceFactory.java
new file mode 100644
index 0000000..5d0d04a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIReferenceFactory.java
@@ -0,0 +1,125 @@
+/**
+ * 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.jms.jndi;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * Converts objects implementing JNDIStorable into a property fields so they can be
+ * stored and regenerated from JNDI
+ *
+ * @since 1.0
+ */
+public class JNDIReferenceFactory implements ObjectFactory {
+
+    /**
+     * This will be called by a JNDIprovider when a Reference is retrieved from
+     * a JNDI store - and generates the original instance
+     *
+     * @param object
+     *        the Reference object
+     * @param name
+     *        the JNDI name
+     * @param nameCtx
+     *        the context
+     * @param environment
+     *        the environment settings used by JNDI
+     *
+     * @return the instance built from the Reference object
+     *
+     * @throws Exception
+     *         if building the instance from Reference fails (usually class not
+     *         found)
+     */
+    @Override
+    public Object getObjectInstance(Object object, Name name, Context nameCtx, Hashtable<?, ?> environment)
+            throws Exception {
+        Object result = null;
+        if (object instanceof Reference) {
+            Reference reference = (Reference) object;
+            Class<?> theClass = loadClass(this, reference.getClassName());
+            if (JNDIStorable.class.isAssignableFrom(theClass)) {
+                JNDIStorable store = (JNDIStorable) theClass.newInstance();
+                Map<String, String> properties = new HashMap<String, String>();
+                for (Enumeration<RefAddr> iter = reference.getAll(); iter.hasMoreElements();) {
+                    StringRefAddr addr = (StringRefAddr) iter.nextElement();
+                    properties.put(addr.getType(), (addr.getContent() == null) ? "" : addr.getContent().toString());
+                }
+                store.setProperties(properties);
+                result = store;
+            }
+        } else {
+            throw new RuntimeException("Object " + object + " is not a reference");
+        }
+        return result;
+    }
+
+    /**
+     * Create a Reference instance from a JNDIStorable object
+     *
+     * @param instanceClassName
+     * @param po
+     * @return Reference
+     * @throws NamingException
+     */
+    public static Reference createReference(String instanceClassName, JNDIStorable po) throws NamingException {
+        Reference result = new Reference(instanceClassName, JNDIReferenceFactory.class.getName(), null);
+        try {
+            Map<String, String> props = po.getProperties();
+            for (Map.Entry<String, String> entry : props.entrySet()) {
+                javax.naming.StringRefAddr addr = new javax.naming.StringRefAddr(entry.getKey(), entry.getValue());
+                result.add(addr);
+            }
+        } catch (Exception e) {
+            throw new NamingException(e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * Retrieve the class loader for a named class
+     *
+     * @param thisObj
+     * @param className
+     * @return the class
+     * @throws ClassNotFoundException
+     */
+    public static Class<?> loadClass(Object thisObj, String className) throws ClassNotFoundException {
+        // try local ClassLoader first.
+        ClassLoader loader = thisObj.getClass().getClassLoader();
+        Class<?> theClass;
+        if (loader != null) {
+            theClass = loader.loadClass(className);
+        } else {
+            // Will be null in jdk1.1.8
+            // use default classLoader
+            theClass = Class.forName(className);
+        }
+        return theClass;
+    }
+}


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


[20/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResource.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResource.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResource.java
new file mode 100644
index 0000000..ee01add
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResource.java
@@ -0,0 +1,35 @@
+/**
+ * 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.jms.meta;
+
+
+/**
+ * Base class for the JMS object representing JMS resources such as Connection, Session, etc.
+ */
+public interface JmsResource {
+
+    /**
+     * Allows a visitor object to walk the resources and process them.
+     *
+     * @param visitor
+     *        The visitor instance that is processing this resource.
+     *
+     * @throws Exception if an error occurs while visiting this resource.
+     */
+    void visit(JmsResourceVistor visitor) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceId.java
new file mode 100644
index 0000000..32ee783
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceId.java
@@ -0,0 +1,56 @@
+/**
+ * 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.jms.meta;
+
+/**
+ * Base for all Id type classes used in the JMS Framework
+ */
+public interface JmsResourceId {
+
+    /**
+     * Allows a Provider to embed a hint in this Id value for later use. The
+     * hint can allow the provider to more easier locate state data for a resource
+     *
+     * @param hint
+     *        The value to add into this Id.
+     */
+    void setProviderHint(Object hint);
+
+    /**
+     * Return the previously stored Provider hint object.
+     *
+     * @return the previously stored Provider hint object.
+     */
+    Object getProviderHint();
+
+    /**
+     * Allows a provider to set it's own internal Id object for this resource
+     * in the case where the JMS framework Id cannot be used directly by the
+     * Provider implementation.
+     *
+     * @param id
+     */
+    void setProviderId(Object id);
+
+    /**
+     * Returns the previously stored Provider Id value.
+     *
+     * @return the previously stored Provider Id value.
+     */
+    Object getProviderId();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceVistor.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceVistor.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceVistor.java
new file mode 100644
index 0000000..1e963d9
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsResourceVistor.java
@@ -0,0 +1,38 @@
+/**
+ * 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.jms.meta;
+
+import org.apache.qpid.jms.JmsDestination;
+
+/**
+ * Visitor interface to make processing JmsResources simpler.
+ */
+public interface JmsResourceVistor {
+
+    void processConnectionInfo(JmsConnectionInfo connectionInfo) throws Exception;
+
+    void processSessionInfo(JmsSessionInfo sessionInfo) throws Exception;
+
+    void processConsumerInfo(JmsConsumerInfo consumerInfo) throws Exception;
+
+    void processProducerInfo(JmsProducerInfo producerInfo) throws Exception;
+
+    void processTransactionInfo(JmsTransactionInfo transactionInfo) throws Exception;
+
+    void processDestination(JmsDestination destination) throws Exception;
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionId.java
new file mode 100644
index 0000000..de0d452
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionId.java
@@ -0,0 +1,100 @@
+/**
+ * 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.jms.meta;
+
+public final class JmsSessionId extends JmsAbstractResourceId implements Comparable<JmsSessionId> {
+
+    private final String connectionId;
+    private final long value;
+
+    protected transient String key;
+    protected transient JmsConnectionId parentId;
+
+    public JmsSessionId(String connectionId, long value) {
+        this.connectionId = connectionId;
+        this.value = value;
+    }
+
+    public JmsSessionId(JmsConnectionId connectionId, long sessionId) {
+        this.connectionId = connectionId.getValue();
+        this.value = sessionId;
+        this.parentId = connectionId;
+    }
+
+    public JmsSessionId(JmsSessionId id) {
+        this.connectionId = id.getConnectionId();
+        this.value = id.getValue();
+    }
+
+    public JmsSessionId(JmsProducerId id) {
+        this.connectionId = id.getConnectionId();
+        this.value = id.getSessionId();
+    }
+
+    public JmsSessionId(JmsConsumerId id) {
+        this.connectionId = id.getConnectionId();
+        this.value = id.getSessionId();
+    }
+
+    public JmsConnectionId getParentId() {
+        if (parentId == null) {
+            parentId = new JmsConnectionId(this);
+        }
+        return parentId;
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) {
+            hashCode = connectionId.hashCode() ^ (int)value;
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || o.getClass() != JmsSessionId.class) {
+            return false;
+        }
+        JmsSessionId id = (JmsSessionId)o;
+        return value == id.value && connectionId.equals(id.connectionId);
+    }
+
+    public String getConnectionId() {
+        return connectionId;
+    }
+
+    public long getValue() {
+        return value;
+    }
+
+    @Override
+    public String toString() {
+        if (key == null) {
+            key = connectionId + ":" + value;
+        }
+        return key;
+    }
+
+    @Override
+    public int compareTo(JmsSessionId other) {
+        return toString().compareTo(other.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
new file mode 100644
index 0000000..04f57d8
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsSessionInfo.java
@@ -0,0 +1,63 @@
+/**
+ * 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.jms.meta;
+
+import javax.jms.Session;
+
+public final class JmsSessionInfo implements JmsResource {
+
+    private final JmsSessionId sessionId;
+    private int acknowledgementMode;
+    private boolean sendAcksAsync;
+
+    public JmsSessionInfo(JmsConnectionInfo connectionMeta, long sessionId) {
+        this.sessionId = new JmsSessionId(connectionMeta.getConnectionId(), sessionId);
+    }
+
+    public JmsSessionInfo(JmsSessionId sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public JmsSessionId getSessionId() {
+        return sessionId;
+    }
+
+    @Override
+    public void visit(JmsResourceVistor vistor) throws Exception {
+        vistor.processSessionInfo(this);
+    }
+
+    public int getAcknowledgementMode() {
+        return acknowledgementMode;
+    }
+
+    public void setAcknowledgementMode(int acknowledgementMode) {
+        this.acknowledgementMode = acknowledgementMode;
+    }
+
+    public boolean isTransacted() {
+        return this.acknowledgementMode == Session.SESSION_TRANSACTED;
+    }
+
+    public boolean isSendAcksAsync() {
+        return sendAcksAsync;
+    }
+
+    public void setSendAcksAsync(boolean sendAcksAsync) {
+        this.sendAcksAsync = sendAcksAsync;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionId.java
new file mode 100644
index 0000000..226aedf
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionId.java
@@ -0,0 +1,81 @@
+/**
+ * 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.jms.meta;
+
+public final class JmsTransactionId extends JmsAbstractResourceId implements Comparable<JmsTransactionId> {
+
+    private final JmsConnectionId connectionId;
+    private final long value;
+
+    private transient String transactionKey;
+
+    public JmsTransactionId(JmsConnectionId connectionId, long transactionId) {
+        this.connectionId = connectionId;
+        this.value = transactionId;
+    }
+
+    public String getTransactionKey() {
+        if (transactionKey == null) {
+            transactionKey = "TX:" + connectionId + ":" + value;
+        }
+        return transactionKey;
+    }
+
+    @Override
+    public String toString() {
+        return getTransactionKey();
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) {
+            hashCode = connectionId.hashCode() ^ (int)value;
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (other == null || other.getClass() != JmsTransactionId.class) {
+            return false;
+        }
+
+        JmsTransactionId tx = (JmsTransactionId) other;
+
+        return value == tx.value && connectionId.equals(tx.connectionId);
+    }
+
+    @Override
+    public int compareTo(JmsTransactionId o) {
+        int result = connectionId.compareTo(o.connectionId);
+        if (result == 0) {
+            result = (int)(value - o.value);
+        }
+        return result;
+    }
+
+    public long getValue() {
+        return value;
+    }
+
+    public JmsConnectionId getConnectionId() {
+        return connectionId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionInfo.java
new file mode 100644
index 0000000..5fca50f
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsTransactionInfo.java
@@ -0,0 +1,90 @@
+/**
+ * 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.jms.meta;
+
+public final class JmsTransactionInfo implements JmsResource, Comparable<JmsTransactionInfo> {
+
+    protected final JmsSessionId sessionId;
+    protected JmsTransactionId transactionId;
+
+    public JmsTransactionInfo(JmsSessionId sessionId, JmsTransactionId transactionId) {
+        this.sessionId = sessionId;
+        this.transactionId = transactionId;
+    }
+
+    public JmsTransactionInfo copy() {
+        return new JmsTransactionInfo(sessionId, transactionId);
+    }
+
+    public JmsSessionId getSessionId() {
+        return sessionId;
+    }
+
+    public JmsTransactionId getTransactionId() {
+        return transactionId;
+    }
+
+    public void setTransactionId(JmsTransactionId transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    public JmsSessionId getParentId() {
+        return this.sessionId;
+    }
+
+    @Override
+    public int hashCode() {
+        return (transactionId == null) ? 0 : transactionId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        JmsTransactionInfo other = (JmsTransactionInfo) obj;
+
+        if (transactionId == null && other.transactionId != null) {
+            return false;
+        } else if (!transactionId.equals(other.transactionId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int compareTo(JmsTransactionInfo other) {
+        return this.transactionId.compareTo(other.transactionId);
+    }
+
+    @Override
+    public String toString() {
+        return "JmsTransactionInfo { " + this.transactionId + " }";
+    }
+
+    @Override
+    public void visit(JmsResourceVistor visitor) throws Exception {
+        visitor.processTransactionInfo(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/package.html
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/package.html b/qpid-jms-client/src/main/java/org/apache/qpid/jms/package.html
new file mode 100644
index 0000000..3d678ce
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/package.html
@@ -0,0 +1,25 @@
+<!--
+    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.
+-->
+<html>
+<head>
+</head>
+<body>
+
+The core AMQP JMS client implementation classes.
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AbstractProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AbstractProvider.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AbstractProvider.java
new file mode 100644
index 0000000..9d743d2
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AbstractProvider.java
@@ -0,0 +1,93 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.qpid.jms.util.IOExceptionSupport;
+
+/**
+ * Base class used to implement the most common features of a Provider instance..
+ *
+ * Methods that are fully optional such as transaction commit and rollback are implemented
+ * here to throw an UnsupportedOperationException.
+ */
+public abstract class AbstractProvider implements Provider {
+
+    protected final URI remoteURI;
+    protected final AtomicBoolean closed = new AtomicBoolean();
+    protected final ScheduledExecutorService serializer;
+
+    protected ProviderListener listener;
+
+    public AbstractProvider(URI remoteURI) {
+        this.remoteURI = remoteURI;
+
+        this.serializer = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+
+            @Override
+            public Thread newThread(Runnable runner) {
+                Thread serial = new Thread(runner);
+                serial.setDaemon(true);
+                serial.setName(toString());
+                return serial;
+            }
+        });
+    }
+
+    @Override
+    public void start() throws IOException, IllegalStateException {
+        checkClosed();
+
+        if (listener == null) {
+            throw new IllegalStateException("No ProviderListener registered.");
+        }
+    }
+
+    @Override
+    public void setProviderListener(ProviderListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public ProviderListener getProviderListener() {
+        return listener;
+    }
+
+    @Override
+    public URI getRemoteURI() {
+        return remoteURI;
+    }
+
+    public void fireProviderException(Throwable ex) {
+        ProviderListener listener = this.listener;
+        if (listener != null) {
+            listener.onConnectionFailure(IOExceptionSupport.create(ex));
+        }
+    }
+
+    protected void checkClosed() throws ProviderClosedException {
+        if (closed.get()) {
+            throw new ProviderClosedException("The Provider is already closed");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AsyncResult.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AsyncResult.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AsyncResult.java
new file mode 100644
index 0000000..b79a3cc
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/AsyncResult.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms.provider;
+
+/**
+ * Defines a result interface for Asynchronous operations.
+ */
+public interface AsyncResult {
+
+    /**
+     * If the operation fails this method is invoked with the Exception
+     * that caused the failure.
+     *
+     * @param result
+     *        The error that resulted in this asynchronous operation failing.
+     */
+    void onFailure(Throwable result);
+
+    /**
+     * If the operation succeeds the resulting value produced is set to null and
+     * the waiting parties are signaled.
+     */
+    void onSuccess();
+
+    /**
+     * Returns true if the AsyncResult has completed.  The task is considered complete
+     * regardless if it succeeded or failed.
+     *
+     * @return returns true if the asynchronous operation has completed.
+     */
+    boolean isComplete();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/DefaultProviderListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/DefaultProviderListener.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/DefaultProviderListener.java
new file mode 100644
index 0000000..e0d3e01
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/DefaultProviderListener.java
@@ -0,0 +1,52 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Default implementation that does nothing for all callbacks.
+ */
+public class DefaultProviderListener implements ProviderListener {
+
+    @Override
+    public void onMessage(JmsInboundMessageDispatch envelope) {
+    }
+
+    @Override
+    public void onConnectionInterrupted(URI remoteURI) {
+    }
+
+    @Override
+    public void onConnectionFailure(IOException ex) {
+    }
+
+    @Override
+    public void onConnectionRecovery(Provider provider) {
+    }
+
+    @Override
+    public void onConnectionRecovered(Provider provider) {
+    }
+
+    @Override
+    public void onConnectionRestored(URI remoteURI) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
new file mode 100644
index 0000000..b8634ea
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/Provider.java
@@ -0,0 +1,292 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+
+/**
+ * Defines the interface that an Implementation of a Specific wire level protocol
+ * provider must implement.  This Provider interface requires that the implementation
+ * methods all operate in an asynchronous manner.
+ */
+public interface Provider {
+
+    /**
+     * Performs the initial low level connection for this provider such as TCP or
+     * SSL connection to a remote Broker.  If this operation fails then the Provider
+     * is considered to be unusable and no further operations should be attempted
+     * using this Provider.
+     *
+     * @throws IOException if the remote resource can not be contacted.
+     */
+    void connect() throws IOException;
+
+    /**
+     * Starts the Provider.  The start method provides a place for the Provider to perform
+     * and pre-start configuration checks to ensure that the current state is valid and that
+     * all contracts have been met prior to starting.
+     *
+     * @throws IOException if an error occurs during start processing.
+     * @throws IllegalStateException if the Provider is improperly configured.
+     */
+    void start() throws IOException, IllegalStateException;
+
+    /**
+     * Closes this Provider terminating all connections and canceling any pending
+     * operations.  The Provider is considered unusable after this call.  This call
+     * is a blocking call and will not return until the Provider has closed or an
+     * error occurs.
+     */
+    void close();
+
+    /**
+     * Returns the URI used to configure this Provider and specify the remote address of the
+     * Broker it connects to.
+     *
+     * @return the URI used to configure this Provider.
+     */
+    URI getRemoteURI();
+
+    /**
+     * Create the Provider version of the given JmsResource.
+     *
+     * For each JMS Resource type the Provider implementation must create it's own internal
+     * representation and upon successful creation provide the caller with a response.  The
+     * Provider should examine the given JmsResource to determine if the given configuration
+     * is supported or can be simulated, or is not supported in which case an exception should be
+     * thrown.
+     *
+     * It is possible for a Provider to indicate that it cannot complete a requested create
+     * either due to some mis-configuration such as bad login credentials on connection create
+     * by throwing a JMSException.  If the Provider does not support creating of the indicated
+     * resource such as a Temporary Queue etc the provider may throw an UnsupportedOperationException
+     * to indicate this.
+     *
+     * @param resource
+     *        The JmsResouce instance that indicates what is being created.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such as bad credentials.
+     */
+    void create(JmsResource resource, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Starts the Provider version of the given JmsResource.
+     *
+     * For some JMS Resources it is necessary or advantageous to have a started state that
+     * must be triggered prior to it's normal use.
+     *
+     * An example of this would be a MessageConsumer which should not receive any incoming
+     * messages until the JMS layer is in a state to handle them.  One such time would be
+     * after connection recovery.  A JMS consumer should normally recover with it's prefetch
+     * value set to zero, or an AMQP link credit of zero and only open up the credit window
+     * once all Connection resources are restored.
+     *
+     * The provider is required to implement this method and not throw any error other than
+     * an IOException if a communication error occurs.  The start operation is not required to
+     * have any effect on the provider resource but must not throw UnsupportedOperation etc.
+     *
+     * @param resource
+     *        The JmsResouce instance that indicates what is being started.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such as already closed resource.
+     */
+    void start(JmsResource resource, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Instruct the Provider to dispose of a given JmsResource.
+     *
+     * The provider is given a JmsResource which it should use to remove any associated
+     * resources and inform the remote Broker instance of the removal of this resource.
+     *
+     * If the Provider cannot destroy the resource due to a non-communication error such as
+     * the logged in user not have role access to destroy the given resource it may throw an
+     * instance of JMSException to indicate such an error.
+     *
+     * @param resource
+     *        The JmsResouce that identifies a previously created JmsResource.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such as not authorized.
+     */
+    void destroy(JmsResource resourceId, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Sends the JmsMessage contained in the outbound dispatch envelope.
+     *
+     * @param envelope
+     *        the message envelope containing the JmsMessage to send.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error that maps to JMS occurs such as not authorized.
+     */
+    void send(JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Called to acknowledge all messages that have been delivered in a given session.
+     *
+     * This method is typically used by a Session that is configured for client acknowledge
+     * mode.  The acknowledgment should only be applied to Messages that have been marked
+     * as delivered and not those still awaiting dispatch.
+     *
+     * @param sessionId
+     *        the ID of the Session whose delivered messages should be acknowledged.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such as unmatched ack.
+     */
+    void acknowledge(JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Called to acknowledge a JmsMessage has been delivered, consumed, re-delivered...etc.
+     *
+     * The provider should perform an acknowledgment for the message based on the configured
+     * mode of the consumer that it was dispatched to and the capabilities of the protocol.
+     *
+     * @param envelope
+     *        The message dispatch envelope containing the Message delivery information.
+     * @param ackType
+     *        The type of acknowledgment being done.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such as unmatched ack.
+     */
+    void acknowledge(JmsInboundMessageDispatch envelope, ACK_TYPE ackType, AsyncResult request)
+        throws IOException, JMSException;
+
+    /**
+     * Called to commit an open transaction.
+     *
+     * If the provider is unable to support transactions then it should throw an
+     * UnsupportedOperationException to indicate this.  The Provider may also throw a
+     * JMSException to indicate a transaction was already rolled back etc.
+     *
+     * @param sessionId
+     *        the Id of the JmsSession that is committing the current transaction.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such not authorized.
+     */
+    void commit(JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Called to roll back an open transaction.
+     *
+     * @param sessionId
+     *        the Id of the JmsSession that is rolling back the current transaction.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such not authorized.
+     */
+    void rollback(JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Called to recover all unacknowledged messages for a Session in client Ack mode.
+     *
+     * @param sessionId
+     *        the Id of the JmsSession that is recovering unacknowledged messages..
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     */
+    void recover(JmsSessionId sessionId, AsyncResult request) throws IOException;
+
+    /**
+     * Remove a durable topic subscription by name.
+     *
+     * A provider can throw an instance of JMSException to indicate that it cannot perform the
+     * un-subscribe operation due to bad security credentials etc.
+     *
+     * @param subscription
+     *        the name of the durable subscription that is to be removed.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     * @throws JMSException if an error occurs due to JMS violation such not authorized.
+     */
+    void unsubscribe(String subscription, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * Request a remote peer send a Message to this client.  A message pull request is
+     * usually only needed in the case where the client sets a zero prefetch limit on the
+     * consumer.  If the consumer has a set prefetch that's greater than zero this method
+     * should just return without performing and action.
+     *
+     * @param timeout
+     *        the amount of time to tell the remote peer to keep this pull request valid.
+     * @param request
+     *        The request object that should be signaled when this operation completes.
+     *
+     * @throws IOException if an error occurs or the Provider is already closed.
+     */
+    void pull(JmsConsumerId consumerId, long timeout, AsyncResult request) throws IOException;
+
+    /**
+     * Gets the Provider specific Message factory for use in the JMS layer when a Session
+     * is asked to create a Message type.  The Provider should implement it's own internal
+     * JmsMessage core to optimize read / write and marshal operations for the connection.
+     *
+     * @returns a JmsMessageFactory instance for use by the JMS layer.
+     */
+    JmsMessageFactory getMessageFactory();
+
+    /**
+     * Sets the listener of events from this Provider instance.
+     *
+     * @param listener
+     *        The listener instance that will receive all event callbacks.
+     */
+    void setProviderListener(ProviderListener listener);
+
+    /**
+     * Gets the currently set ProdiverListener instance.
+     *
+     * @return the currently set ProviderListener instance.
+     */
+    ProviderListener getProviderListener();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderClosedException.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderClosedException.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderClosedException.java
new file mode 100644
index 0000000..1e00b58
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderClosedException.java
@@ -0,0 +1,28 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+
+public class ProviderClosedException extends IOException {
+
+    private static final long serialVersionUID = 1L;
+
+    public ProviderClosedException(String message) {
+        super(message);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderConstants.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderConstants.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderConstants.java
new file mode 100644
index 0000000..4e3f90c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderConstants.java
@@ -0,0 +1,43 @@
+/**
+ * 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.jms.provider;
+
+/**
+ * Set of Provider specific constants used when interacting with the Provider API.
+ */
+public final class ProviderConstants {
+
+    private ProviderConstants() {}
+
+    public enum ACK_TYPE {
+        DELIVERED(0),
+        CONSUMED(1),
+        REDELIVERED(2),
+        POISONED(3),
+        EXPIRED(4);
+
+        private final int value;
+
+        private ACK_TYPE(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFactory.java
new file mode 100644
index 0000000..c07518e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFactory.java
@@ -0,0 +1,110 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.qpid.jms.util.FactoryFinder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Interface that all JMS Providers must implement.
+ */
+public abstract class ProviderFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ProviderFactory.class);
+
+    private static final FactoryFinder<ProviderFactory> PROVIDER_FACTORY_FINDER =
+        new FactoryFinder<ProviderFactory>(ProviderFactory.class,
+            "META-INF/services/" + ProviderFactory.class.getPackage().getName().replace(".", "/") + "/");
+
+    /**
+     * Creates an instance of the given AsyncProvider and configures it using the
+     * properties set on the given remote broker URI.
+     *
+     * @param remoteURI
+     *        The URI used to connect to a remote Broker.
+     *
+     * @return a new AsyncProvider instance.
+     *
+     * @throws Exception if an error occurs while creating the Provider instance.
+     */
+    public abstract Provider createAsyncProvider(URI remoteURI) throws Exception;
+
+    /**
+     * @return the name of this JMS Provider, e.g. STOMP, AMQP, MQTT...etc
+     */
+    public abstract String getName();
+
+    /**
+     * Static create method that performs the ProviderFactory search and handles the
+     * configuration and setup.
+     *
+     * @param remoteURI
+     *        the URI of the remote peer.
+     *
+     * @return a new AsyncProvider instance that is ready for use.
+     *
+     * @throws Exception if an error occurs while creating the AsyncProvider instance.
+     */
+    public static Provider createAsync(URI remoteURI) throws Exception {
+        Provider result = null;
+
+        try {
+            ProviderFactory factory = findProviderFactory(remoteURI);
+            result = factory.createAsyncProvider(remoteURI);
+            result.connect();
+        } catch (Exception ex) {
+            LOG.error("Failed to create BlockingProvider instance for: {}", remoteURI.getScheme());
+            LOG.trace("Error: ", ex);
+            throw ex;
+        }
+
+        return result;
+    }
+
+    /**
+     * Searches for a ProviderFactory by using the scheme from the given URI.
+     *
+     * The search first checks the local cache of provider factories before moving on
+     * to search in the class path.
+     *
+     * @param location
+     *        The URI whose scheme will be used to locate a ProviderFactory.
+     *
+     * @return a provider factory instance matching the URI's scheme.
+     *
+     * @throws IOException if an error occurs while locating the factory.
+     */
+    public static ProviderFactory findProviderFactory(URI location) throws IOException {
+        String scheme = location.getScheme();
+        if (scheme == null) {
+            throw new IOException("No Provider scheme specified: [" + location + "]");
+        }
+
+        ProviderFactory factory = null;
+        try {
+            factory = PROVIDER_FACTORY_FINDER.newInstance(scheme);
+        } catch (Throwable e) {
+            throw new IOException("Provider scheme NOT recognized: [" + scheme + "]", e);
+        }
+
+        return factory;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFuture.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFuture.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFuture.java
new file mode 100644
index 0000000..7a52ad3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderFuture.java
@@ -0,0 +1,109 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.qpid.jms.util.IOExceptionSupport;
+
+/**
+ * Asynchronous Provider Future class.
+ */
+public class ProviderFuture implements AsyncResult {
+
+    protected final CountDownLatch latch = new CountDownLatch(1);
+    protected Throwable error;
+    protected final AsyncResult watcher;
+
+    public ProviderFuture() {
+        this.watcher = null;
+    }
+
+    public ProviderFuture(AsyncResult watcher) {
+        this.watcher = watcher;
+    }
+
+    @Override
+    public boolean isComplete() {
+        return latch.getCount() == 0;
+    }
+
+    @Override
+    public void onFailure(Throwable result) {
+        error = result;
+        latch.countDown();
+        if (watcher != null) {
+            watcher.onFailure(error);
+        }
+    }
+
+    @Override
+    public void onSuccess() {
+        latch.countDown();
+        if (watcher != null) {
+            watcher.onSuccess();
+        }
+    }
+
+    /**
+     * Timed wait for a response to a Provider operation.
+     *
+     * @param amount
+     *        The amount of time to wait before abandoning the wait.
+     * @param unit
+     *        The unit to use for this wait period.
+     *
+     * @return the result of this operation or null if the wait timed out.
+     *
+     * @throws IOException if an error occurs while waiting for the response.
+     */
+    public void sync(long amount, TimeUnit unit) throws IOException {
+        try {
+            latch.await(amount, unit);
+        } catch (InterruptedException e) {
+            Thread.interrupted();
+            throw IOExceptionSupport.create(e);
+        }
+        failOnError();
+    }
+
+    /**
+     * Waits for a response to some Provider requested operation.
+     *
+     * @return the response from the Provider for this operation.
+     *
+     * @throws IOException if an error occurs while waiting for the response.
+     */
+    public void sync() throws IOException {
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            Thread.interrupted();
+            throw IOExceptionSupport.create(e);
+        }
+        failOnError();
+    }
+
+    private void failOnError() throws IOException {
+        Throwable cause = error;
+        if (cause != null) {
+            throw IOExceptionSupport.create(cause);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderListener.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderListener.java
new file mode 100644
index 0000000..18938d5
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderListener.java
@@ -0,0 +1,103 @@
+/**
+ * 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.jms.provider;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Events interface used to update the listener with changes in provider state.
+ */
+public interface ProviderListener {
+
+    /**
+     * Called when a new Message has arrived for a registered consumer.
+     *
+     * @param envelope
+     *        The dispatch object containing the message and delivery information.
+     */
+    void onMessage(JmsInboundMessageDispatch envelope);
+
+    /**
+     * Called from a fault tolerant Provider instance to signal that the underlying
+     * connection to the Broker has been lost.  The Provider will attempt to reconnect
+     * following this event unless closed.
+     *
+     * It is considered a programming error to allow any exceptions to be thrown from
+     * this notification method.
+     *
+     * @param remoteURI
+     *        The URI of the Broker whose connection was lost.
+     */
+    void onConnectionInterrupted(URI remoteURI);
+
+    /**
+     * Called to indicate that a connection to the Broker has been reestablished and
+     * that notified listener should start to recover it's state.  The provider will
+     * not transition to the recovered state until the listener notifies the provider
+     * that recovery is complete.
+     *
+     * @param provider
+     *        The new Provider instance that will become active after the state
+     *        has been recovered.
+     *
+     * @throws Exception if an error occurs during recovery attempt, this will fail
+     *         the Provider that's being used for recovery.
+     */
+    void onConnectionRecovery(Provider provider) throws Exception;
+
+    /**
+     * Called to indicate that a connection to the Broker has been reestablished and
+     * that all recovery operations have succeeded and the connection will now be
+     * transitioned to a recovered state.  This method gives the listener a chance
+     * so send any necessary post recovery commands such as consumer start or message
+     * pull for a zero prefetch consumer etc.
+     *
+     * @param provider
+     *        The new Provider instance that will become active after the state
+     *        has been recovered.
+     *
+     * @throws Exception if an error occurs during recovery attempt, this will fail
+     *         the Provider that's being used for recovery.
+     */
+    void onConnectionRecovered(Provider provider) throws Exception;
+
+    /**
+     * Called to signal that all recovery operations are now complete and the Provider
+     * is again in a normal connected state.
+     *
+     * It is considered a programming error to allow any exceptions to be thrown from
+     * this notification method.
+     *
+     * @param remoteURI
+     *        The URI of the Broker that the client has now connected to.
+     */
+    void onConnectionRestored(URI remoteURI);
+
+    /**
+     * Called to indicate that the underlying connection to the Broker has been lost and
+     * the Provider will not perform any reconnect.  Following this call the provider is
+     * in a failed state and further calls to it will throw an Exception.
+     *
+     * @param ex
+     *        The exception that indicates the cause of this Provider failure.
+     */
+    void onConnectionFailure(IOException ex);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.java
new file mode 100644
index 0000000..1381dba
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/ProviderWrapper.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.jms.provider;
+
+import java.io.IOException;
+import java.net.URI;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+
+/**
+ * Allows one AsyncProvider instance to wrap around another and provide some additional
+ * features beyond the normal AsyncProvider interface.
+ *
+ * This wrapper is meant primarily for Providers that are adding some additional feature
+ * on-top of an existing provider such as a discovery based provider that only needs to
+ * pass along discovered remote peer information.
+ */
+public class ProviderWrapper<E extends Provider> implements Provider, ProviderListener {
+
+    protected final E next;
+    protected ProviderListener listener;
+
+    public ProviderWrapper(E next) {
+        this.next = next;
+        this.next.setProviderListener(this);
+    }
+
+    @Override
+    public void connect() throws IOException {
+        next.connect();
+    }
+
+    @Override
+    public void start() throws IOException, IllegalStateException {
+        if (this.listener == null) {
+            throw new IllegalStateException("Cannot start with null ProviderListener");
+        }
+        next.start();
+    }
+
+    @Override
+    public void close() {
+        next.close();
+    }
+
+    @Override
+    public URI getRemoteURI() {
+        return next.getRemoteURI();
+    }
+
+    @Override
+    public void create(JmsResource resource, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        next.create(resource, request);
+    }
+
+    @Override
+    public void start(JmsResource resource, AsyncResult request) throws IOException, JMSException {
+        next.start(resource, request);
+    }
+
+    @Override
+    public void destroy(JmsResource resourceId, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        next.destroy(resourceId, request);
+    }
+
+    @Override
+    public void send(JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException {
+        next.send(envelope, request);
+    }
+
+    @Override
+    public void acknowledge(JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException {
+        next.acknowledge(sessionId, request);
+    }
+
+    @Override
+    public void acknowledge(JmsInboundMessageDispatch envelope, ACK_TYPE ackType, AsyncResult request) throws IOException, JMSException {
+        next.acknowledge(envelope, ackType, request);
+    }
+
+    @Override
+    public void commit(JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        next.commit(sessionId, request);
+    }
+
+    @Override
+    public void rollback(JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        next.rollback(sessionId, request);
+    }
+
+    @Override
+    public void recover(JmsSessionId sessionId, AsyncResult request) throws IOException, UnsupportedOperationException {
+        next.recover(sessionId, request);
+    }
+
+    @Override
+    public void unsubscribe(String subscription, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        next.unsubscribe(subscription, request);
+    }
+
+    @Override
+    public void pull(JmsConsumerId consumerId, long timeout, AsyncResult request) throws IOException, UnsupportedOperationException {
+        next.pull(consumerId, timeout, request);
+    }
+
+    @Override
+    public JmsMessageFactory getMessageFactory() {
+        return next.getMessageFactory();
+    }
+
+    @Override
+    public void setProviderListener(ProviderListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public ProviderListener getProviderListener() {
+        return this.listener;
+    }
+
+    @Override
+    public void onMessage(JmsInboundMessageDispatch envelope) {
+        this.listener.onMessage(envelope);
+    }
+
+    @Override
+    public void onConnectionInterrupted(URI remoteURI) {
+        this.listener.onConnectionInterrupted(remoteURI);
+    }
+
+    @Override
+    public void onConnectionRecovery(Provider provider) throws Exception {
+        this.listener.onConnectionRecovery(provider);
+    }
+
+    @Override
+    public void onConnectionRecovered(Provider provider) throws Exception {
+        this.listener.onConnectionRecovered(provider);
+    }
+
+    @Override
+    public void onConnectionRestored(URI remoteURI) {
+        this.listener.onConnectionRestored(remoteURI);
+    }
+
+    @Override
+    public void onConnectionFailure(IOException ex) {
+        this.listener.onConnectionInterrupted(this.next.getRemoteURI());
+    }
+
+    /**
+     * @return the wrapped AsyncProvider.
+     */
+    public Provider getNext() {
+        return this.next;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AbstractAmqpResource.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AbstractAmqpResource.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AbstractAmqpResource.java
new file mode 100644
index 0000000..1175b34
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AbstractAmqpResource.java
@@ -0,0 +1,242 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+
+import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
+
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.transport.AmqpError;
+import org.apache.qpid.proton.amqp.transport.ErrorCondition;
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract base for all AmqpResource implementations to extend.
+ *
+ * This abstract class wraps up the basic state management bits so that the concrete
+ * object don't have to reproduce it.  Provides hooks for the subclasses to initialize
+ * and shutdown.
+ */
+public abstract class AbstractAmqpResource<R extends JmsResource, E extends Endpoint> implements AmqpResource {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractAmqpResource.class);
+
+    protected AsyncResult openRequest;
+    protected AsyncResult closeRequest;
+
+    protected E endpoint;
+    protected R info;
+
+    /**
+     * Creates a new AbstractAmqpResource instance with the JmsResource provided, and
+     * sets the Endpoint to null.
+     *
+     * @param info
+     *        The JmsResource instance that this AmqpResource is managing.
+     */
+    public AbstractAmqpResource(R info) {
+        this(info, null);
+    }
+
+    /**
+     * Creates a new AbstractAmqpResource instance with the JmsResource provided, and
+     * sets the Endpoint to the given value.
+     *
+     * @param info
+     *        The JmsResource instance that this AmqpResource is managing.
+     * @param endpoint
+     *        The Proton Endpoint instance that this object maps to.
+     */
+    public AbstractAmqpResource(R info, E endpoint) {
+        this.info = info;
+        this.endpoint = endpoint;
+    }
+
+    @Override
+    public void open(AsyncResult request) {
+        this.openRequest = request;
+        doOpen();
+        this.endpoint.setContext(this);
+        this.endpoint.open();
+    }
+
+    @Override
+    public boolean isOpen() {
+        return this.endpoint.getRemoteState() == EndpointState.ACTIVE;
+    }
+
+    @Override
+    public boolean isAwaitingOpen() {
+        return this.openRequest != null;
+    }
+
+    @Override
+    public void opened() {
+        if (this.openRequest != null) {
+            this.openRequest.onSuccess();
+            this.openRequest = null;
+        }
+    }
+
+    @Override
+    public void close(AsyncResult request) {
+        // If already closed signal success or else the caller might never get notified.
+        if (endpoint.getLocalState() == EndpointState.CLOSED) {
+            request.onSuccess();
+            return;
+        }
+
+        this.closeRequest = request;
+        doClose();
+        this.endpoint.close();
+    }
+
+    @Override
+    public boolean isClosed() {
+        return this.endpoint.getLocalState() == EndpointState.CLOSED;
+    }
+
+    @Override
+    public boolean isAwaitingClose() {
+        return this.closeRequest != null;
+    }
+
+    @Override
+    public void closed() {
+        if (this.closeRequest != null) {
+            this.closeRequest.onSuccess();
+            this.closeRequest = null;
+        }
+
+        this.endpoint.close();
+        this.endpoint.free();
+    }
+
+    @Override
+    public void failed() {
+        failed(new JMSException("Remote request failed."));
+    }
+
+    @Override
+    public void failed(Exception cause) {
+        if (openRequest != null) {
+            openRequest.onFailure(cause);
+            openRequest = null;
+        }
+
+        if (closeRequest != null) {
+            closeRequest.onFailure(cause);
+            closeRequest = null;
+        }
+    }
+
+    public E getEndpoint() {
+        return this.endpoint;
+    }
+
+    public R getJmsResource() {
+        return this.info;
+    }
+
+    public EndpointState getLocalState() {
+        if (endpoint == null) {
+            return EndpointState.UNINITIALIZED;
+        }
+        return this.endpoint.getLocalState();
+    }
+
+    public EndpointState getRemoteState() {
+        if (endpoint == null) {
+            return EndpointState.UNINITIALIZED;
+        }
+        return this.endpoint.getRemoteState();
+    }
+
+    @Override
+    public Exception getRemoteError() {
+        String message = getRemoteErrorMessage();
+        Exception remoteError = null;
+        Symbol error = endpoint.getRemoteCondition().getCondition();
+        if (error.equals(AmqpError.UNAUTHORIZED_ACCESS)) {
+            remoteError = new JMSSecurityException(message);
+        } else {
+            remoteError = new JMSException(message);
+        }
+
+        return remoteError;
+    }
+
+    @Override
+    public String getRemoteErrorMessage() {
+        String message = "Received unkown error from remote peer";
+        if (endpoint.getRemoteCondition() != null) {
+            ErrorCondition error = endpoint.getRemoteCondition();
+            if (error.getDescription() != null && !error.getDescription().isEmpty()) {
+                message = error.getDescription();
+            }
+        }
+
+        return message;
+    }
+
+    @Override
+    public void processStateChange() throws IOException {
+        EndpointState remoteState = endpoint.getRemoteState();
+
+        if (remoteState == EndpointState.ACTIVE) {
+            if (isAwaitingOpen()) {
+                LOG.debug("{} is now open: ", this);
+                opened();
+            }
+
+            // Should not receive an ACTIVE event if not awaiting the open state.
+        } else if (remoteState == EndpointState.CLOSED) {
+            if (isAwaitingClose()) {
+                LOG.debug("{} is now closed: ", this);
+                closed();
+            } else if (isAwaitingOpen()) {
+                // Error on Open, create exception and signal failure.
+                LOG.warn("Open of {} failed: ", this);
+                Exception remoteError = this.getRemoteError();
+                failed(remoteError);
+            } else {
+                // TODO - Handle remote asynchronous close.
+                LOG.warn("{} was closed remotely.", this);
+            }
+        }
+    }
+
+    @Override
+    public void processDeliveryUpdates() throws IOException {
+    }
+
+    @Override
+    public void processFlowUpdates() throws IOException {
+    }
+
+    protected abstract void doOpen();
+
+    protected abstract void doClose();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpAnonymousProducer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpAnonymousProducer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpAnonymousProducer.java
new file mode 100644
index 0000000..7da3143
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpAnonymousProducer.java
@@ -0,0 +1,192 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsProducerId;
+import org.apache.qpid.jms.meta.JmsProducerInfo;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.util.IdGenerator;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handles the case of anonymous JMS MessageProducers.
+ *
+ * In order to simulate the anonymous producer we must create a sender for each message
+ * send attempt and close it following a successful send.
+ */
+public class AmqpAnonymousProducer extends AmqpProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpAnonymousProducer.class);
+    private static final IdGenerator producerIdGenerator = new IdGenerator();
+
+    private final String producerIdKey = producerIdGenerator.generateId();
+    private long producerIdCount;
+
+    /**
+     * Creates the Anonymous Producer object.
+     *
+     * @param session
+     *        the session that owns this producer
+     * @param info
+     *        the JmsProducerInfo for this producer.
+     */
+    public AmqpAnonymousProducer(AmqpSession session, JmsProducerInfo info) {
+        super(session, info);
+    }
+
+    @Override
+    public boolean send(JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException {
+
+        LOG.trace("Started send chain for anonymous producer: {}", getProducerId());
+
+        // Create a new ProducerInfo for the short lived producer that's created to perform the
+        // send to the given AMQP target.
+        JmsProducerInfo info = new JmsProducerInfo(getNextProducerId());
+        info.setDestination(envelope.getDestination());
+
+        // We open a Fixed Producer instance with the target destination.  Once it opens
+        // it will trigger the open event which will in turn trigger the send event and
+        // when that succeeds it will trigger a close which completes the send chain.
+        AmqpFixedProducer producer = new AmqpFixedProducer(session, info);
+        producer.setPresettle(isPresettle());
+        AnonymousOpenRequest open = new AnonymousOpenRequest(request, producer, envelope);
+        producer.open(open);
+
+        return true;
+    }
+
+    @Override
+    public void open(AsyncResult request) {
+        // Trigger an immediate open, we don't talk to the Broker until
+        // a send occurs so we must not let the client block.
+        request.onSuccess();
+    }
+
+    @Override
+    public void close(AsyncResult request) {
+        // Trigger an immediate close, the internal producers that are currently in a send
+        // will track their own state and close as the send completes or fails.
+        request.onSuccess();
+    }
+
+    @Override
+    protected void doOpen() {
+    }
+
+    @Override
+    protected void doClose() {
+    }
+
+    @Override
+    public boolean isAnonymous() {
+        return true;
+    }
+
+    @Override
+    public EndpointState getLocalState() {
+        return EndpointState.ACTIVE;
+    }
+
+    @Override
+    public EndpointState getRemoteState() {
+        return EndpointState.ACTIVE;
+    }
+
+    private JmsProducerId getNextProducerId() {
+        return new JmsProducerId(producerIdKey, -1, producerIdCount++);
+    }
+
+    private abstract class AnonymousRequest implements AsyncResult {
+
+        protected final AsyncResult sendResult;
+        protected final AmqpProducer producer;
+        protected final JmsOutboundMessageDispatch envelope;
+
+        public AnonymousRequest(AsyncResult sendResult, AmqpProducer producer, JmsOutboundMessageDispatch envelope) {
+            this.sendResult = sendResult;
+            this.producer = producer;
+            this.envelope = envelope;
+        }
+
+        @Override
+        public boolean isComplete() {
+            return sendResult.isComplete();
+        }
+
+        /**
+         * In all cases of the chain of events that make up the send for an anonymous
+         * producer a failure will trigger the original send request to fail.
+         */
+        @Override
+        public void onFailure(Throwable result) {
+            LOG.debug("Send failed during {} step in chain: {}", this.getClass().getName(), getProducerId());
+            sendResult.onFailure(result);
+        }
+    }
+
+    private final class AnonymousOpenRequest extends AnonymousRequest {
+
+        public AnonymousOpenRequest(AsyncResult sendResult, AmqpProducer producer, JmsOutboundMessageDispatch envelope) {
+            super(sendResult, producer, envelope);
+        }
+
+        @Override
+        public void onSuccess() {
+            LOG.trace("Open phase of anonymous send complete: {} ", getProducerId());
+            AnonymousSendRequest send = new AnonymousSendRequest(this);
+            try {
+                producer.send(envelope, send);
+            } catch (Exception e) {
+                sendResult.onFailure(e);
+            }
+        }
+    }
+
+    private final class AnonymousSendRequest extends AnonymousRequest {
+
+        public AnonymousSendRequest(AnonymousOpenRequest open) {
+            super(open.sendResult, open.producer, open.envelope);
+        }
+
+        @Override
+        public void onSuccess() {
+            LOG.trace("Send phase of anonymous send complete: {} ", getProducerId());
+            AnonymousCloseRequest close = new AnonymousCloseRequest(this);
+            producer.close(close);
+        }
+    }
+
+    private final class AnonymousCloseRequest extends AnonymousRequest {
+
+        public AnonymousCloseRequest(AnonymousSendRequest send) {
+            super(send.sendResult, send.producer, send.envelope);
+        }
+
+        @Override
+        public void onSuccess() {
+            LOG.trace("Close phase of anonymous send complete: {} ", getProducerId());
+            sendResult.onSuccess();
+        }
+    }
+}


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


[07/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/generate-list-sections.xsl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/generate-list-sections.xsl b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/generate-list-sections.xsl
new file mode 100644
index 0000000..82ae80b
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/generate-list-sections.xsl
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+                xmlns:exsl="http://exslt.org/common"
+                extension-element-prefixes="exsl">
+
+<!-- Used to generate the Java classes in this package.
+     Changes to these classes should be effected by modifying this stylesheet then re-running it,
+     using a stylesheet processor that understands the exsl directives such as xsltproc -->
+
+<xsl:template match="/">
+    <xsl:variable name="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.
+ *
+ */
+</xsl:variable>
+
+    <xsl:for-each select="descendant-or-self::node()[name()='type']">
+        <xsl:variable name="classname"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>DescribedType</xsl:variable>
+        <xsl:if test="@provides = 'section'">
+            <xsl:if test="@name = 'header' or @name='properties'">
+              <xsl:call-template name="typeClass">
+                  <xsl:with-param name="license" select="$license"/>
+                  <xsl:with-param name="classname" select="$classname"/>
+              </xsl:call-template>
+            </xsl:if>
+        </xsl:if>
+
+    </xsl:for-each>
+</xsl:template>
+
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="typeClass">
+    <xsl:param name="license"/>
+    <xsl:param name="classname"/>
+  <exsl:document href="{$classname}.java" method="text">
+  <xsl:value-of select="$license"/>
+package org.apache.qpid.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-list-sections.xsl, which resides in this package.
+ */
+public class <xsl:value-of select="$classname"/> extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("<xsl:value-of select="descendant::node()[name()='descriptor']/@name"/>");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(<xsl:value-of select="concat(substring(descendant::node()[name()='descriptor']/@code,1,10),substring(descendant::node()[name()='descriptor']/@code,14))"/>L);
+
+<xsl:for-each select="descendant::node()[name()='field']">
+    private static final int FIELD_<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template> = <xsl:value-of select="count(preceding-sibling::node()[name()='field'])"/>;</xsl:for-each>
+
+    public <xsl:value-of select="$classname"/>(Object... fields)
+    {
+        super(<xsl:value-of select="count(descendant::node()[name()='field'])"/>);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+<xsl:for-each select="descendant::node()[name()='field']">
+    public <xsl:value-of select="$classname"/> set<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>(Object o)
+    {
+        getFields()[FIELD_<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>] = o;
+        return this;
+    }
+</xsl:for-each>
+}
+
+</exsl:document>
+
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="constructFromLiteral">
+    <xsl:param name="type"/>
+    <xsl:param name="value"/>
+    <xsl:choose>
+        <xsl:when test="$type = 'string'">"<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'symbol'">Symbol.valueOf("<xsl:value-of select="$value"/>")</xsl:when>
+        <xsl:when test="$type = 'ubyte'">UnsignedByte.valueOf((byte) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ushort'">UnsignedShort.valueOf((short) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'uint'">UnsignedInteger.valueOf(<xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ulong'">UnsignedLong.valueOf(<xsl:value-of select="$value"/>L)</xsl:when>
+        <xsl:when test="$type = 'long'"><xsl:value-of select="$value"/>L</xsl:when>
+        <xsl:when test="$type = 'short'">(short)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'short'">(byte)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
+    </xsl:choose>
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+<xsl:template name="substringAfterLast"><xsl:param name="input"/><xsl:param name="arg"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,$arg)"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input"><xsl:value-of select="substring-after($input,$arg)"/></xsl:with-param><xsl:with-param name="arg"><xsl:value-of select="$arg"/></xsl:with-param></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$input"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="initCap"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="initLower"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="toUpper"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:template>
+
+    <xsl:template name="toUpperDashToUnderscore"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz-','ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/></xsl:template>
+
+    <xsl:template name="dashToCamel">
+        <xsl:param name="input"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,'-')"><xsl:call-template name="initCap"><xsl:with-param name="input" select="substring-before($input,'-')"/></xsl:call-template><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="substring-after($input,'-')"/></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:call-template name="initCap"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="dashToLowerCamel">
+        <xsl:param name="input"/>
+        <xsl:call-template name="initLower"><xsl:with-param name="input"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:with-param></xsl:call-template>
+    </xsl:template>
+</xsl:stylesheet>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/AttachMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/AttachMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/AttachMatcher.java
new file mode 100644
index 0000000..edd62cd
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/AttachMatcher.java
@@ -0,0 +1,231 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class AttachMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        NAME,
+        HANDLE,
+        ROLE,
+        SND_SETTLE_MODE,
+        RCV_SETTLE_MODE,
+        SOURCE,
+        TARGET,
+        UNSETTLED,
+        INCOMPLETE_UNSETTLED,
+        INITIAL_DELIVERY_COUNT,
+        MAX_MESSAGE_SIZE,
+        OFFERED_CAPABILITIES,
+        DESIRED_CAPABILITIES,
+        PROPERTIES,
+    }
+
+    public AttachMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000012L),
+              Symbol.valueOf("amqp:attach:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public AttachMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public AttachMatcher withName(Matcher<?> m)
+    {
+        getMatchers().put(Field.NAME, m);
+        return this;
+    }
+
+    public AttachMatcher withHandle(Matcher<?> m)
+    {
+        getMatchers().put(Field.HANDLE, m);
+        return this;
+    }
+
+    public AttachMatcher withRole(Matcher<?> m)
+    {
+        getMatchers().put(Field.ROLE, m);
+        return this;
+    }
+
+    public AttachMatcher withSndSettleMode(Matcher<?> m)
+    {
+        getMatchers().put(Field.SND_SETTLE_MODE, m);
+        return this;
+    }
+
+    public AttachMatcher withRcvSettleMode(Matcher<?> m)
+    {
+        getMatchers().put(Field.RCV_SETTLE_MODE, m);
+        return this;
+    }
+
+    public AttachMatcher withSource(Matcher<?> m)
+    {
+        getMatchers().put(Field.SOURCE, m);
+        return this;
+    }
+
+    public AttachMatcher withTarget(Matcher<?> m)
+    {
+        getMatchers().put(Field.TARGET, m);
+        return this;
+    }
+
+    public AttachMatcher withUnsettled(Matcher<?> m)
+    {
+        getMatchers().put(Field.UNSETTLED, m);
+        return this;
+    }
+
+    public AttachMatcher withIncompleteUnsettled(Matcher<?> m)
+    {
+        getMatchers().put(Field.INCOMPLETE_UNSETTLED, m);
+        return this;
+    }
+
+    public AttachMatcher withInitialDeliveryCount(Matcher<?> m)
+    {
+        getMatchers().put(Field.INITIAL_DELIVERY_COUNT, m);
+        return this;
+    }
+
+    public AttachMatcher withMaxMessageSize(Matcher<?> m)
+    {
+        getMatchers().put(Field.MAX_MESSAGE_SIZE, m);
+        return this;
+    }
+
+    public AttachMatcher withOfferedCapabilities(Matcher<?> m)
+    {
+        getMatchers().put(Field.OFFERED_CAPABILITIES, m);
+        return this;
+    }
+
+    public AttachMatcher withDesiredCapabilities(Matcher<?> m)
+    {
+        getMatchers().put(Field.DESIRED_CAPABILITIES, m);
+        return this;
+    }
+
+    public AttachMatcher withProperties(Matcher<?> m)
+    {
+        getMatchers().put(Field.PROPERTIES, m);
+        return this;
+    }
+
+    public Object getReceivedName()
+    {
+        return getReceivedFields().get(Field.NAME);
+    }
+
+    public Object getReceivedHandle()
+    {
+        return getReceivedFields().get(Field.HANDLE);
+    }
+
+    public Object getReceivedRole()
+    {
+        return getReceivedFields().get(Field.ROLE);
+    }
+
+    public Object getReceivedSndSettleMode()
+    {
+        return getReceivedFields().get(Field.SND_SETTLE_MODE);
+    }
+
+    public Object getReceivedRcvSettleMode()
+    {
+        return getReceivedFields().get(Field.RCV_SETTLE_MODE);
+    }
+
+    public Object getReceivedSource()
+    {
+        return getReceivedFields().get(Field.SOURCE);
+    }
+
+    public Object getReceivedTarget()
+    {
+        return getReceivedFields().get(Field.TARGET);
+    }
+
+    public Object getReceivedUnsettled()
+    {
+        return getReceivedFields().get(Field.UNSETTLED);
+    }
+
+    public Object getReceivedIncompleteUnsettled()
+    {
+        return getReceivedFields().get(Field.INCOMPLETE_UNSETTLED);
+    }
+
+    public Object getReceivedInitialDeliveryCount()
+    {
+        return getReceivedFields().get(Field.INITIAL_DELIVERY_COUNT);
+    }
+
+    public Object getReceivedMaxMessageSize()
+    {
+        return getReceivedFields().get(Field.MAX_MESSAGE_SIZE);
+    }
+
+    public Object getReceivedOfferedCapabilities()
+    {
+        return getReceivedFields().get(Field.OFFERED_CAPABILITIES);
+    }
+
+    public Object getReceivedDesiredCapabilities()
+    {
+        return getReceivedFields().get(Field.DESIRED_CAPABILITIES);
+    }
+
+    public Object getReceivedProperties()
+    {
+        return getReceivedFields().get(Field.PROPERTIES);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/BeginMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/BeginMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/BeginMatcher.java
new file mode 100644
index 0000000..ede5a31
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/BeginMatcher.java
@@ -0,0 +1,159 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class BeginMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        REMOTE_CHANNEL,
+        NEXT_OUTGOING_ID,
+        INCOMING_WINDOW,
+        OUTGOING_WINDOW,
+        HANDLE_MAX,
+        OFFERED_CAPABILITIES,
+        DESIRED_CAPABILITIES,
+        PROPERTIES,
+    }
+
+    public BeginMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000011L),
+              Symbol.valueOf("amqp:begin:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public BeginMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public BeginMatcher withRemoteChannel(Matcher<?> m)
+    {
+        getMatchers().put(Field.REMOTE_CHANNEL, m);
+        return this;
+    }
+
+    public BeginMatcher withNextOutgoingId(Matcher<?> m)
+    {
+        getMatchers().put(Field.NEXT_OUTGOING_ID, m);
+        return this;
+    }
+
+    public BeginMatcher withIncomingWindow(Matcher<?> m)
+    {
+        getMatchers().put(Field.INCOMING_WINDOW, m);
+        return this;
+    }
+
+    public BeginMatcher withOutgoingWindow(Matcher<?> m)
+    {
+        getMatchers().put(Field.OUTGOING_WINDOW, m);
+        return this;
+    }
+
+    public BeginMatcher withHandleMax(Matcher<?> m)
+    {
+        getMatchers().put(Field.HANDLE_MAX, m);
+        return this;
+    }
+
+    public BeginMatcher withOfferedCapabilities(Matcher<?> m)
+    {
+        getMatchers().put(Field.OFFERED_CAPABILITIES, m);
+        return this;
+    }
+
+    public BeginMatcher withDesiredCapabilities(Matcher<?> m)
+    {
+        getMatchers().put(Field.DESIRED_CAPABILITIES, m);
+        return this;
+    }
+
+    public BeginMatcher withProperties(Matcher<?> m)
+    {
+        getMatchers().put(Field.PROPERTIES, m);
+        return this;
+    }
+
+    public Object getReceivedRemoteChannel()
+    {
+        return getReceivedFields().get(Field.REMOTE_CHANNEL);
+    }
+
+    public Object getReceivedNextOutgoingId()
+    {
+        return getReceivedFields().get(Field.NEXT_OUTGOING_ID);
+    }
+
+    public Object getReceivedIncomingWindow()
+    {
+        return getReceivedFields().get(Field.INCOMING_WINDOW);
+    }
+
+    public Object getReceivedOutgoingWindow()
+    {
+        return getReceivedFields().get(Field.OUTGOING_WINDOW);
+    }
+
+    public Object getReceivedHandleMax()
+    {
+        return getReceivedFields().get(Field.HANDLE_MAX);
+    }
+
+    public Object getReceivedOfferedCapabilities()
+    {
+        return getReceivedFields().get(Field.OFFERED_CAPABILITIES);
+    }
+
+    public Object getReceivedDesiredCapabilities()
+    {
+        return getReceivedFields().get(Field.DESIRED_CAPABILITIES);
+    }
+
+    public Object getReceivedProperties()
+    {
+        return getReceivedFields().get(Field.PROPERTIES);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/CloseMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/CloseMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/CloseMatcher.java
new file mode 100644
index 0000000..ac03a5c
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/CloseMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class CloseMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        ERROR,
+    }
+
+    public CloseMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000018L),
+              Symbol.valueOf("amqp:close:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public CloseMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public CloseMatcher withError(Matcher<?> m)
+    {
+        getMatchers().put(Field.ERROR, m);
+        return this;
+    }
+
+    public Object getReceivedError()
+    {
+        return getReceivedFields().get(Field.ERROR);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DetachMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DetachMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DetachMatcher.java
new file mode 100644
index 0000000..dc5d2f1
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DetachMatcher.java
@@ -0,0 +1,99 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class DetachMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        HANDLE,
+        CLOSED,
+        ERROR,
+    }
+
+    public DetachMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000016L),
+              Symbol.valueOf("amqp:detach:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public DetachMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public DetachMatcher withHandle(Matcher<?> m)
+    {
+        getMatchers().put(Field.HANDLE, m);
+        return this;
+    }
+
+    public DetachMatcher withClosed(Matcher<?> m)
+    {
+        getMatchers().put(Field.CLOSED, m);
+        return this;
+    }
+
+    public DetachMatcher withError(Matcher<?> m)
+    {
+        getMatchers().put(Field.ERROR, m);
+        return this;
+    }
+
+    public Object getReceivedHandle()
+    {
+        return getReceivedFields().get(Field.HANDLE);
+    }
+
+    public Object getReceivedClosed()
+    {
+        return getReceivedFields().get(Field.CLOSED);
+    }
+
+    public Object getReceivedError()
+    {
+        return getReceivedFields().get(Field.ERROR);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DispositionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DispositionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DispositionMatcher.java
new file mode 100644
index 0000000..3d41fee
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/DispositionMatcher.java
@@ -0,0 +1,135 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class DispositionMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        ROLE,
+        FIRST,
+        LAST,
+        SETTLED,
+        STATE,
+        BATCHABLE,
+    }
+
+    public DispositionMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000015L),
+              Symbol.valueOf("amqp:disposition:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public DispositionMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public DispositionMatcher withRole(Matcher<?> m)
+    {
+        getMatchers().put(Field.ROLE, m);
+        return this;
+    }
+
+    public DispositionMatcher withFirst(Matcher<?> m)
+    {
+        getMatchers().put(Field.FIRST, m);
+        return this;
+    }
+
+    public DispositionMatcher withLast(Matcher<?> m)
+    {
+        getMatchers().put(Field.LAST, m);
+        return this;
+    }
+
+    public DispositionMatcher withSettled(Matcher<?> m)
+    {
+        getMatchers().put(Field.SETTLED, m);
+        return this;
+    }
+
+    public DispositionMatcher withState(Matcher<?> m)
+    {
+        getMatchers().put(Field.STATE, m);
+        return this;
+    }
+
+    public DispositionMatcher withBatchable(Matcher<?> m)
+    {
+        getMatchers().put(Field.BATCHABLE, m);
+        return this;
+    }
+
+    public Object getReceivedRole()
+    {
+        return getReceivedFields().get(Field.ROLE);
+    }
+
+    public Object getReceivedFirst()
+    {
+        return getReceivedFields().get(Field.FIRST);
+    }
+
+    public Object getReceivedLast()
+    {
+        return getReceivedFields().get(Field.LAST);
+    }
+
+    public Object getReceivedSettled()
+    {
+        return getReceivedFields().get(Field.SETTLED);
+    }
+
+    public Object getReceivedState()
+    {
+        return getReceivedFields().get(Field.STATE);
+    }
+
+    public Object getReceivedBatchable()
+    {
+        return getReceivedFields().get(Field.BATCHABLE);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/EndMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/EndMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/EndMatcher.java
new file mode 100644
index 0000000..460bbaa
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/EndMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class EndMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        ERROR,
+    }
+
+    public EndMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000017L),
+              Symbol.valueOf("amqp:end:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public EndMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public EndMatcher withError(Matcher<?> m)
+    {
+        getMatchers().put(Field.ERROR, m);
+        return this;
+    }
+
+    public Object getReceivedError()
+    {
+        return getReceivedFields().get(Field.ERROR);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/FlowMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/FlowMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/FlowMatcher.java
new file mode 100644
index 0000000..9f6f74b
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/FlowMatcher.java
@@ -0,0 +1,195 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class FlowMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        NEXT_INCOMING_ID,
+        INCOMING_WINDOW,
+        NEXT_OUTGOING_ID,
+        OUTGOING_WINDOW,
+        HANDLE,
+        DELIVERY_COUNT,
+        LINK_CREDIT,
+        AVAILABLE,
+        DRAIN,
+        ECHO,
+        PROPERTIES,
+    }
+
+    public FlowMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000013L),
+              Symbol.valueOf("amqp:flow:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public FlowMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public FlowMatcher withNextIncomingId(Matcher<?> m)
+    {
+        getMatchers().put(Field.NEXT_INCOMING_ID, m);
+        return this;
+    }
+
+    public FlowMatcher withIncomingWindow(Matcher<?> m)
+    {
+        getMatchers().put(Field.INCOMING_WINDOW, m);
+        return this;
+    }
+
+    public FlowMatcher withNextOutgoingId(Matcher<?> m)
+    {
+        getMatchers().put(Field.NEXT_OUTGOING_ID, m);
+        return this;
+    }
+
+    public FlowMatcher withOutgoingWindow(Matcher<?> m)
+    {
+        getMatchers().put(Field.OUTGOING_WINDOW, m);
+        return this;
+    }
+
+    public FlowMatcher withHandle(Matcher<?> m)
+    {
+        getMatchers().put(Field.HANDLE, m);
+        return this;
+    }
+
+    public FlowMatcher withDeliveryCount(Matcher<?> m)
+    {
+        getMatchers().put(Field.DELIVERY_COUNT, m);
+        return this;
+    }
+
+    public FlowMatcher withLinkCredit(Matcher<?> m)
+    {
+        getMatchers().put(Field.LINK_CREDIT, m);
+        return this;
+    }
+
+    public FlowMatcher withAvailable(Matcher<?> m)
+    {
+        getMatchers().put(Field.AVAILABLE, m);
+        return this;
+    }
+
+    public FlowMatcher withDrain(Matcher<?> m)
+    {
+        getMatchers().put(Field.DRAIN, m);
+        return this;
+    }
+
+    public FlowMatcher withEcho(Matcher<?> m)
+    {
+        getMatchers().put(Field.ECHO, m);
+        return this;
+    }
+
+    public FlowMatcher withProperties(Matcher<?> m)
+    {
+        getMatchers().put(Field.PROPERTIES, m);
+        return this;
+    }
+
+    public Object getReceivedNextIncomingId()
+    {
+        return getReceivedFields().get(Field.NEXT_INCOMING_ID);
+    }
+
+    public Object getReceivedIncomingWindow()
+    {
+        return getReceivedFields().get(Field.INCOMING_WINDOW);
+    }
+
+    public Object getReceivedNextOutgoingId()
+    {
+        return getReceivedFields().get(Field.NEXT_OUTGOING_ID);
+    }
+
+    public Object getReceivedOutgoingWindow()
+    {
+        return getReceivedFields().get(Field.OUTGOING_WINDOW);
+    }
+
+    public Object getReceivedHandle()
+    {
+        return getReceivedFields().get(Field.HANDLE);
+    }
+
+    public Object getReceivedDeliveryCount()
+    {
+        return getReceivedFields().get(Field.DELIVERY_COUNT);
+    }
+
+    public Object getReceivedLinkCredit()
+    {
+        return getReceivedFields().get(Field.LINK_CREDIT);
+    }
+
+    public Object getReceivedAvailable()
+    {
+        return getReceivedFields().get(Field.AVAILABLE);
+    }
+
+    public Object getReceivedDrain()
+    {
+        return getReceivedFields().get(Field.DRAIN);
+    }
+
+    public Object getReceivedEcho()
+    {
+        return getReceivedFields().get(Field.ECHO);
+    }
+
+    public Object getReceivedProperties()
+    {
+        return getReceivedFields().get(Field.PROPERTIES);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/OpenMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/OpenMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/OpenMatcher.java
new file mode 100644
index 0000000..fd0bf61
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/OpenMatcher.java
@@ -0,0 +1,183 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class OpenMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        CONTAINER_ID,
+        HOSTNAME,
+        MAX_FRAME_SIZE,
+        CHANNEL_MAX,
+        IDLE_TIME_OUT,
+        OUTGOING_LOCALES,
+        INCOMING_LOCALES,
+        OFFERED_CAPABILITIES,
+        DESIRED_CAPABILITIES,
+        PROPERTIES,
+    }
+
+    public OpenMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000010L),
+              Symbol.valueOf("amqp:open:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public OpenMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public OpenMatcher withContainerId(Matcher<?> m)
+    {
+        getMatchers().put(Field.CONTAINER_ID, m);
+        return this;
+    }
+
+    public OpenMatcher withHostname(Matcher<?> m)
+    {
+        getMatchers().put(Field.HOSTNAME, m);
+        return this;
+    }
+
+    public OpenMatcher withMaxFrameSize(Matcher<?> m)
+    {
+        getMatchers().put(Field.MAX_FRAME_SIZE, m);
+        return this;
+    }
+
+    public OpenMatcher withChannelMax(Matcher<?> m)
+    {
+        getMatchers().put(Field.CHANNEL_MAX, m);
+        return this;
+    }
+
+    public OpenMatcher withIdleTimeOut(Matcher<?> m)
+    {
+        getMatchers().put(Field.IDLE_TIME_OUT, m);
+        return this;
+    }
+
+    public OpenMatcher withOutgoingLocales(Matcher<?> m)
+    {
+        getMatchers().put(Field.OUTGOING_LOCALES, m);
+        return this;
+    }
+
+    public OpenMatcher withIncomingLocales(Matcher<?> m)
+    {
+        getMatchers().put(Field.INCOMING_LOCALES, m);
+        return this;
+    }
+
+    public OpenMatcher withOfferedCapabilities(Matcher<?> m)
+    {
+        getMatchers().put(Field.OFFERED_CAPABILITIES, m);
+        return this;
+    }
+
+    public OpenMatcher withDesiredCapabilities(Matcher<?> m)
+    {
+        getMatchers().put(Field.DESIRED_CAPABILITIES, m);
+        return this;
+    }
+
+    public OpenMatcher withProperties(Matcher<?> m)
+    {
+        getMatchers().put(Field.PROPERTIES, m);
+        return this;
+    }
+
+    public Object getReceivedContainerId()
+    {
+        return getReceivedFields().get(Field.CONTAINER_ID);
+    }
+
+    public Object getReceivedHostname()
+    {
+        return getReceivedFields().get(Field.HOSTNAME);
+    }
+
+    public Object getReceivedMaxFrameSize()
+    {
+        return getReceivedFields().get(Field.MAX_FRAME_SIZE);
+    }
+
+    public Object getReceivedChannelMax()
+    {
+        return getReceivedFields().get(Field.CHANNEL_MAX);
+    }
+
+    public Object getReceivedIdleTimeOut()
+    {
+        return getReceivedFields().get(Field.IDLE_TIME_OUT);
+    }
+
+    public Object getReceivedOutgoingLocales()
+    {
+        return getReceivedFields().get(Field.OUTGOING_LOCALES);
+    }
+
+    public Object getReceivedIncomingLocales()
+    {
+        return getReceivedFields().get(Field.INCOMING_LOCALES);
+    }
+
+    public Object getReceivedOfferedCapabilities()
+    {
+        return getReceivedFields().get(Field.OFFERED_CAPABILITIES);
+    }
+
+    public Object getReceivedDesiredCapabilities()
+    {
+        return getReceivedFields().get(Field.DESIRED_CAPABILITIES);
+    }
+
+    public Object getReceivedProperties()
+    {
+        return getReceivedFields().get(Field.PROPERTIES);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslChallengeMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslChallengeMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslChallengeMatcher.java
new file mode 100644
index 0000000..08b0bc7
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslChallengeMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class SaslChallengeMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        CHALLENGE,
+    }
+
+    public SaslChallengeMatcher()
+    {
+        super(FrameType.SASL,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000042L),
+              Symbol.valueOf("amqp:sasl-challenge:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public SaslChallengeMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public SaslChallengeMatcher withChallenge(Matcher<?> m)
+    {
+        getMatchers().put(Field.CHALLENGE, m);
+        return this;
+    }
+
+    public Object getReceivedChallenge()
+    {
+        return getReceivedFields().get(Field.CHALLENGE);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslInitMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslInitMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslInitMatcher.java
new file mode 100644
index 0000000..7284edb
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslInitMatcher.java
@@ -0,0 +1,99 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class SaslInitMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        MECHANISM,
+        INITIAL_RESPONSE,
+        HOSTNAME,
+    }
+
+    public SaslInitMatcher()
+    {
+        super(FrameType.SASL,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000041L),
+              Symbol.valueOf("amqp:sasl-init:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public SaslInitMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public SaslInitMatcher withMechanism(Matcher<?> m)
+    {
+        getMatchers().put(Field.MECHANISM, m);
+        return this;
+    }
+
+    public SaslInitMatcher withInitialResponse(Matcher<?> m)
+    {
+        getMatchers().put(Field.INITIAL_RESPONSE, m);
+        return this;
+    }
+
+    public SaslInitMatcher withHostname(Matcher<?> m)
+    {
+        getMatchers().put(Field.HOSTNAME, m);
+        return this;
+    }
+
+    public Object getReceivedMechanism()
+    {
+        return getReceivedFields().get(Field.MECHANISM);
+    }
+
+    public Object getReceivedInitialResponse()
+    {
+        return getReceivedFields().get(Field.INITIAL_RESPONSE);
+    }
+
+    public Object getReceivedHostname()
+    {
+        return getReceivedFields().get(Field.HOSTNAME);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslMechanismsMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslMechanismsMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslMechanismsMatcher.java
new file mode 100644
index 0000000..63fd913
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslMechanismsMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class SaslMechanismsMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        SASL_SERVER_MECHANISMS,
+    }
+
+    public SaslMechanismsMatcher()
+    {
+        super(FrameType.SASL,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000040L),
+              Symbol.valueOf("amqp:sasl-mechanisms:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public SaslMechanismsMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public SaslMechanismsMatcher withSaslServerMechanisms(Matcher<?> m)
+    {
+        getMatchers().put(Field.SASL_SERVER_MECHANISMS, m);
+        return this;
+    }
+
+    public Object getReceivedSaslServerMechanisms()
+    {
+        return getReceivedFields().get(Field.SASL_SERVER_MECHANISMS);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslOutcomeMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslOutcomeMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslOutcomeMatcher.java
new file mode 100644
index 0000000..22355d1
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslOutcomeMatcher.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class SaslOutcomeMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        CODE,
+        ADDITIONAL_DATA,
+    }
+
+    public SaslOutcomeMatcher()
+    {
+        super(FrameType.SASL,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000044L),
+              Symbol.valueOf("amqp:sasl-outcome:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public SaslOutcomeMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public SaslOutcomeMatcher withCode(Matcher<?> m)
+    {
+        getMatchers().put(Field.CODE, m);
+        return this;
+    }
+
+    public SaslOutcomeMatcher withAdditionalData(Matcher<?> m)
+    {
+        getMatchers().put(Field.ADDITIONAL_DATA, m);
+        return this;
+    }
+
+    public Object getReceivedCode()
+    {
+        return getReceivedFields().get(Field.CODE);
+    }
+
+    public Object getReceivedAdditionalData()
+    {
+        return getReceivedFields().get(Field.ADDITIONAL_DATA);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslResponseMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslResponseMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslResponseMatcher.java
new file mode 100644
index 0000000..c5fb865
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/SaslResponseMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithNoPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class SaslResponseMatcher extends FrameWithNoPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        RESPONSE,
+    }
+
+    public SaslResponseMatcher()
+    {
+        super(FrameType.SASL,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000043L),
+              Symbol.valueOf("amqp:sasl-response:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public SaslResponseMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public SaslResponseMatcher withResponse(Matcher<?> m)
+    {
+        getMatchers().put(Field.RESPONSE, m);
+        return this;
+    }
+
+    public Object getReceivedResponse()
+    {
+        return getReceivedFields().get(Field.RESPONSE);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/TransferMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/TransferMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/TransferMatcher.java
new file mode 100644
index 0000000..d7274a1
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/TransferMatcher.java
@@ -0,0 +1,195 @@
+/*
+ * 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.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.FrameWithPayloadMatchingHandler;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class TransferMatcher extends FrameWithPayloadMatchingHandler
+{
+    /** Note that the ordinals of the Field enums match the order specified in the spec */
+    public enum Field
+    {
+        HANDLE,
+        DELIVERY_ID,
+        DELIVERY_TAG,
+        MESSAGE_FORMAT,
+        SETTLED,
+        MORE,
+        RCV_SETTLE_MODE,
+        STATE,
+        RESUME,
+        ABORTED,
+        BATCHABLE,
+    }
+
+    public TransferMatcher()
+    {
+        super(FrameType.AMQP,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(0x0000000000000014L),
+              Symbol.valueOf("amqp:transfer:list"),
+              new HashMap<Enum<?>, Matcher<?>>(),
+              null);
+    }
+
+    @Override
+    public TransferMatcher onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+
+    public TransferMatcher withHandle(Matcher<?> m)
+    {
+        getMatchers().put(Field.HANDLE, m);
+        return this;
+    }
+
+    public TransferMatcher withDeliveryId(Matcher<?> m)
+    {
+        getMatchers().put(Field.DELIVERY_ID, m);
+        return this;
+    }
+
+    public TransferMatcher withDeliveryTag(Matcher<?> m)
+    {
+        getMatchers().put(Field.DELIVERY_TAG, m);
+        return this;
+    }
+
+    public TransferMatcher withMessageFormat(Matcher<?> m)
+    {
+        getMatchers().put(Field.MESSAGE_FORMAT, m);
+        return this;
+    }
+
+    public TransferMatcher withSettled(Matcher<?> m)
+    {
+        getMatchers().put(Field.SETTLED, m);
+        return this;
+    }
+
+    public TransferMatcher withMore(Matcher<?> m)
+    {
+        getMatchers().put(Field.MORE, m);
+        return this;
+    }
+
+    public TransferMatcher withRcvSettleMode(Matcher<?> m)
+    {
+        getMatchers().put(Field.RCV_SETTLE_MODE, m);
+        return this;
+    }
+
+    public TransferMatcher withState(Matcher<?> m)
+    {
+        getMatchers().put(Field.STATE, m);
+        return this;
+    }
+
+    public TransferMatcher withResume(Matcher<?> m)
+    {
+        getMatchers().put(Field.RESUME, m);
+        return this;
+    }
+
+    public TransferMatcher withAborted(Matcher<?> m)
+    {
+        getMatchers().put(Field.ABORTED, m);
+        return this;
+    }
+
+    public TransferMatcher withBatchable(Matcher<?> m)
+    {
+        getMatchers().put(Field.BATCHABLE, m);
+        return this;
+    }
+
+    public Object getReceivedHandle()
+    {
+        return getReceivedFields().get(Field.HANDLE);
+    }
+
+    public Object getReceivedDeliveryId()
+    {
+        return getReceivedFields().get(Field.DELIVERY_ID);
+    }
+
+    public Object getReceivedDeliveryTag()
+    {
+        return getReceivedFields().get(Field.DELIVERY_TAG);
+    }
+
+    public Object getReceivedMessageFormat()
+    {
+        return getReceivedFields().get(Field.MESSAGE_FORMAT);
+    }
+
+    public Object getReceivedSettled()
+    {
+        return getReceivedFields().get(Field.SETTLED);
+    }
+
+    public Object getReceivedMore()
+    {
+        return getReceivedFields().get(Field.MORE);
+    }
+
+    public Object getReceivedRcvSettleMode()
+    {
+        return getReceivedFields().get(Field.RCV_SETTLE_MODE);
+    }
+
+    public Object getReceivedState()
+    {
+        return getReceivedFields().get(Field.STATE);
+    }
+
+    public Object getReceivedResume()
+    {
+        return getReceivedFields().get(Field.RESUME);
+    }
+
+    public Object getReceivedAborted()
+    {
+        return getReceivedFields().get(Field.ABORTED);
+    }
+
+    public Object getReceivedBatchable()
+    {
+        return getReceivedFields().get(Field.BATCHABLE);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/generate-matchers.xsl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/generate-matchers.xsl b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/generate-matchers.xsl
new file mode 100644
index 0000000..263c87f
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/generate-matchers.xsl
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+                xmlns:exsl="http://exslt.org/common"
+                extension-element-prefixes="exsl">
+
+<!-- Used to generate the Java classes in this package.
+     Changes to these classes should be effected by modifying this stylesheet then re-running it,
+     using a stylesheet processor that understands the exsl directives such as xsltproc -->
+
+<xsl:template match="/">
+    <xsl:variable name="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.
+ *
+ */
+</xsl:variable>
+
+    <xsl:for-each select="descendant-or-self::node()[name()='type']">
+        <xsl:variable name="classname"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>Matcher</xsl:variable>
+        <xsl:variable name="superclass">
+            <xsl:choose>
+                <xsl:when test="@name = 'transfer'">FrameWithPayloadMatchingHandler</xsl:when>
+                <xsl:otherwise>FrameWithNoPayloadMatchingHandler</xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
+        <xsl:if test="@provides = 'frame' or @provides = 'sasl-frame'">
+          <xsl:call-template name="typeClass">
+              <xsl:with-param name="license" select="$license"/>
+              <xsl:with-param name="classname" select="$classname"/>
+              <xsl:with-param name="superclass" select="$superclass"/>
+          </xsl:call-template>
+        </xsl:if>
+
+    </xsl:for-each>
+</xsl:template>
+
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="typeClass">
+    <xsl:param name="license"/>
+    <xsl:param name="classname"/>
+    <xsl:param name="superclass"/>
+  <exsl:document href="{$classname}.java" method="text">
+  <xsl:value-of select="$license"/>
+package org.apache.qpid.jms.test.testpeer.matchers;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.FrameType;
+import org.apache.qpid.jms.test.testpeer.<xsl:value-of select="$superclass"/>;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-matchers.xsl, which resides in this package.
+ */
+public class <xsl:value-of select="$classname"/> extends <xsl:value-of select="$superclass"/>
+{
+    /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+    public enum Field
+    {
+<xsl:for-each select="descendant::node()[name()='field']">
+<xsl:text>        </xsl:text><xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>,
+</xsl:for-each>    }
+
+    public <xsl:value-of select="$classname"/>()
+    {
+        super(FrameType.<xsl:choose><xsl:when test="@provides='sasl-frame'">SASL</xsl:when><xsl:otherwise>AMQP</xsl:otherwise></xsl:choose>,
+              ANY_CHANNEL,
+              UnsignedLong.valueOf(<xsl:value-of select="concat(substring(descendant::node()[name()='descriptor']/@code,1,10),substring(descendant::node()[name()='descriptor']/@code,14))"/>L),
+              Symbol.valueOf("<xsl:value-of select="descendant::node()[name()='descriptor']/@name"/>"),
+              new HashMap&lt;Enum&lt;?&gt;, Matcher&lt;?&gt;&gt;(),
+              null);
+    }
+
+    @Override
+    public <xsl:value-of select="$classname"/> onSuccess(Runnable onSuccessAction)
+    {
+        super.onSuccess(onSuccessAction);
+        return this;
+    }
+<xsl:for-each select="descendant::node()[name()='field']">
+    public <xsl:value-of select="$classname"/> with<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>(Matcher&lt;?&gt; m)
+    {
+        getMatchers().put(Field.<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>, m);
+        return this;
+    }
+</xsl:for-each>
+<xsl:for-each select="descendant::node()[name()='field']">
+    public Object getReceived<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>()
+    {
+        return getReceivedFields().get(Field.<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>);
+    }
+</xsl:for-each>
+    @Override
+    protected Enum&lt;?&gt; getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+
+</exsl:document>
+
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="constructFromLiteral">
+    <xsl:param name="type"/>
+    <xsl:param name="value"/>
+    <xsl:choose>
+        <xsl:when test="$type = 'string'">"<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'symbol'">Symbol.valueOf("<xsl:value-of select="$value"/>")</xsl:when>
+        <xsl:when test="$type = 'ubyte'">UnsignedByte.valueOf((byte) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ushort'">UnsignedShort.valueOf((short) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'uint'">UnsignedInteger.valueOf(<xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ulong'">UnsignedLong.valueOf(<xsl:value-of select="$value"/>L)</xsl:when>
+        <xsl:when test="$type = 'long'"><xsl:value-of select="$value"/>L</xsl:when>
+        <xsl:when test="$type = 'short'">(short)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'short'">(byte)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
+    </xsl:choose>
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+<xsl:template name="substringAfterLast"><xsl:param name="input"/><xsl:param name="arg"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,$arg)"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input"><xsl:value-of select="substring-after($input,$arg)"/></xsl:with-param><xsl:with-param name="arg"><xsl:value-of select="$arg"/></xsl:with-param></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$input"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="initCap"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="initLower"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="toUpper"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:template>
+
+    <xsl:template name="toUpperDashToUnderscore"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz-','ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/></xsl:template>
+
+    <xsl:template name="dashToCamel">
+        <xsl:param name="input"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,'-')"><xsl:call-template name="initCap"><xsl:with-param name="input" select="substring-before($input,'-')"/></xsl:call-template><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="substring-after($input,'-')"/></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:call-template name="initCap"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="dashToLowerCamel">
+        <xsl:param name="input"/>
+        <xsl:call-template name="initLower"><xsl:with-param name="input"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:with-param></xsl:call-template>
+    </xsl:template>
+</xsl:stylesheet>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/AbstractMessageSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/AbstractMessageSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/AbstractMessageSectionMatcher.java
new file mode 100644
index 0000000..133a452
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/AbstractMessageSectionMatcher.java
@@ -0,0 +1,138 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Map;
+
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.proton.codec.Data;
+import org.hamcrest.Matcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractMessageSectionMatcher
+{
+    private final Logger _logger = LoggerFactory.getLogger(getClass());
+
+    private final UnsignedLong _numericDescriptor;
+    private final Symbol _symbolicDescriptor;
+
+    private final Map<Object, Matcher<?>> _fieldMatchers;
+    private Map<Object, Object> _receivedFields;
+
+    private final boolean _expectTrailingBytes;
+
+    protected AbstractMessageSectionMatcher(UnsignedLong numericDescriptor,
+                                            Symbol symbolicDescriptor,
+                                            Map<Object, Matcher<?>> fieldMatchers,
+                                            boolean expectTrailingBytes)
+    {
+        _numericDescriptor = numericDescriptor;
+        _symbolicDescriptor = symbolicDescriptor;
+        _fieldMatchers = fieldMatchers;
+        _expectTrailingBytes = expectTrailingBytes;
+    }
+
+    protected Map<Object, Matcher<?>> getMatchers()
+    {
+        return _fieldMatchers;
+    }
+
+    protected Map<Object, Object> getReceivedFields()
+    {
+        return _receivedFields;
+    }
+
+    /**
+     * @return the number of bytes consumed from the provided Binary
+     * @throws RuntimeException if the provided Binary does not match expectation in some way
+     */
+    public int verify(Binary receivedBinary) throws RuntimeException
+    {
+        int length = receivedBinary.getLength();
+        Data data = Proton.data(length);
+        long decoded = data.decode(receivedBinary.asByteBuffer());
+        if(decoded > Integer.MAX_VALUE)
+        {
+            throw new IllegalStateException("Decoded more bytes than Binary supports holding");
+        }
+
+        if(decoded < length && !_expectTrailingBytes)
+        {
+            throw new IllegalArgumentException("Expected to consume all bytes, but trailing bytes remain: Got "
+                                        + length + ", consumed "+ decoded);
+        }
+
+        DescribedType decodedDescribedType = data.getDescribedType();
+        verifyReceivedDescribedType(decodedDescribedType);
+
+        //Need to cast to int, but verified earlier that it is < Integer.MAX_VALUE
+        return (int) decoded;
+    }
+
+    private void verifyReceivedDescribedType(DescribedType decodedDescribedType)
+    {
+        Object descriptor = decodedDescribedType.getDescriptor();
+        if(!(_symbolicDescriptor.equals(descriptor) || _numericDescriptor.equals(descriptor)))
+        {
+            throw new IllegalArgumentException("Unexpected section type descriptor. Expected "
+                    + _symbolicDescriptor + " or " + _numericDescriptor + ", but got: " + descriptor);
+        }
+
+        verifyReceivedDescribedObject(decodedDescribedType.getDescribed());
+    }
+
+    /**
+     * sub-classes should implement depending on the expected content of the particular section type.
+     */
+    protected abstract void verifyReceivedDescribedObject(Object describedObject);
+
+    /**
+     * Utility method for use by sub-classes that expect field-based sections, i.e lists or maps.
+     */
+    protected void verifyReceivedFields(Map<Object, Object> valueMap)
+    {
+        _receivedFields = valueMap;
+
+        _logger.debug("About to check the fields of the section."
+                + "\n  Received:" + valueMap
+                + "\n  Expectations: " + _fieldMatchers);
+        for(Map.Entry<Object, Matcher<?>> entry : _fieldMatchers.entrySet())
+        {
+            @SuppressWarnings("unchecked")
+            Matcher<Object> matcher = (Matcher<Object>) entry.getValue();
+            Object field = entry.getKey();
+            assertThat("Field " + field + " value should match", valueMap.get(field), matcher);
+        }
+    }
+
+    /**
+     * Intended to be overridden in most cases that use the above method (but not necessarily all - hence not marked as abstract)
+     */
+    protected Enum<?> getField(int fieldIndex)
+    {
+        throw new UnsupportedOperationException("getFieldName is expected to be overridden by subclass if it is required");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/ApplicationPropertiesSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/ApplicationPropertiesSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/ApplicationPropertiesSectionMatcher.java
new file mode 100644
index 0000000..87735fc
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/ApplicationPropertiesSectionMatcher.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public class ApplicationPropertiesSectionMatcher extends MessageMapSectionMatcher
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:application-properties:map");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000074L);
+
+    public ApplicationPropertiesSectionMatcher(boolean expectTrailingBytes)
+    {
+        super(DESCRIPTOR_CODE,
+              DESCRIPTOR_SYMBOL,
+              new HashMap<Object, Matcher<?>>(),
+              expectTrailingBytes);
+    }
+
+    @Override
+    public ApplicationPropertiesSectionMatcher withEntry(Object key, Matcher<?> m)
+    {
+        if(!(key instanceof String))
+        {
+            throw new RuntimeException("ApplicationProperties maps must use non-null String keys");
+        }
+
+        return (ApplicationPropertiesSectionMatcher) super.withEntry(key, m);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageAnnotationsSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageAnnotationsSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageAnnotationsSectionMatcher.java
new file mode 100644
index 0000000..754d32a
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageAnnotationsSectionMatcher.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public class MessageAnnotationsSectionMatcher extends MessageMapSectionMatcher
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:message-annotations:map");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000072L);
+
+    public MessageAnnotationsSectionMatcher(boolean expectTrailingBytes)
+    {
+        super(DESCRIPTOR_CODE,
+              DESCRIPTOR_SYMBOL,
+              new HashMap<Object, Matcher<?>>(),
+              expectTrailingBytes);
+    }
+
+    @Override
+    public MessageAnnotationsSectionMatcher withEntry(Object key, Matcher<?> m)
+    {
+        validateType(key);
+
+        return (MessageAnnotationsSectionMatcher) super.withEntry(key, m);
+    }
+
+    private void validateType(Object key)
+    {
+        if(!(key instanceof Long || key instanceof Symbol))
+        {
+            throw new IllegalArgumentException("Message Annotation keys must be of type Symbol or long (reserved)");
+        }
+    }
+
+    public boolean keyExistsInReceivedAnnotations(Object key)
+    {
+        validateType(key);
+
+        Map<Object, Object> receivedFields = super.getReceivedFields();
+
+        if(receivedFields != null)
+        {
+            return receivedFields.containsKey(key);
+        }
+        else
+        {
+            return false;
+        }
+    }
+}
+


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


[23/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java
new file mode 100644
index 0000000..1dfd0b3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java
@@ -0,0 +1,119 @@
+/**
+ * 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.jms.jndi;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+
+/**
+ * Facilitates objects to be stored in JNDI as properties
+ *
+ * @since 1.0
+ */
+public abstract class JNDIStorable implements Referenceable, Externalizable {
+
+    private Map<String, String> properties;
+
+    /**
+     * Set the properties that will represent the instance in JNDI
+     *
+     * @param props
+     */
+    protected abstract void buildFromProperties(Map<String, String> props);
+
+    /**
+     * Initialize the instance from properties stored in JNDI
+     *
+     * @param props
+     */
+    protected abstract void populateProperties(Map<String, String> props);
+
+    /**
+     * set the properties for this instance as retrieved from JNDI
+     *
+     * @param props
+     */
+    public synchronized void setProperties(Map<String, String> props) {
+        this.properties = props;
+        buildFromProperties(props);
+    }
+
+    /**
+     * Get the properties from this instance for storing in JNDI
+     *
+     * @return the properties
+     */
+    public synchronized Map<String, String> getProperties() {
+        if (this.properties == null) {
+            this.properties = new HashMap<String, String>();
+        }
+        populateProperties(this.properties);
+        return this.properties;
+    }
+
+    /**
+     * Retrieve a Reference for this instance to store in JNDI
+     *
+     * @return the built Reference
+     * @throws NamingException
+     *         if error on building Reference
+     */
+    @Override
+    public Reference getReference() throws NamingException {
+        return JNDIReferenceFactory.createReference(this.getClass().getName(), this);
+    }
+
+    /**
+     * @param in
+     * @throws IOException
+     * @throws ClassNotFoundException
+     * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
+     */
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        Map<String, String> props = (Map<String, String>) in.readObject();
+        if (props != null) {
+            setProperties(props);
+        }
+    }
+
+    /**
+     * @param out
+     * @throws IOException
+     * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
+     */
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(getProperties());
+    }
+
+    protected String getProperty(Map<String, String> map, String key, String defaultValue) {
+        String value = map.get(key);
+        if (value != null) {
+            return value;
+        }
+        return defaultValue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java
new file mode 100644
index 0000000..8ad7b32
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java
@@ -0,0 +1,197 @@
+/**
+ * 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.jms.jndi;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.JmsTopic;
+
+/**
+ * A factory of the StompJms InitialContext which contains
+ * {@link javax.jms.ConnectionFactory} instances as well as a child context
+ * called <i>destinations</i> which contain all of the current active
+ * destinations, in child context depending on the QoS such as transient or
+ * durable and queue or topic.
+ *
+ * @since 1.0
+ */
+public class JmsInitialContextFactory implements InitialContextFactory {
+
+    private static final String[] DEFAULT_CONNECTION_FACTORY_NAMES = {
+        "ConnectionFactory", "QueueConnectionFactory", "TopicConnectionFactory" };
+
+    private String connectionPrefix = "";
+
+    String queuePrefix = "/queue/";
+    String topicPrefix = "/topic/";
+
+    @Override
+    public Context getInitialContext(Hashtable environment) throws NamingException {
+
+        queuePrefix = getValue(environment, "queuePrefix", queuePrefix);
+        topicPrefix = getValue(environment, "topicPrefix", topicPrefix);
+
+        // lets create a factory
+        Map<String, Object> data = new ConcurrentHashMap<String, Object>();
+        String[] names = getConnectionFactoryNames(environment);
+        for (int i = 0; i < names.length; i++) {
+            JmsConnectionFactory factory = null;
+            String name = names[i];
+
+            try {
+                factory = createConnectionFactory(name, environment);
+            } catch (Exception e) {
+                throw new NamingException("Invalid broker URL");
+
+            }
+
+            data.put(name, factory);
+        }
+
+        data.put("queue", new LazyCreateContext() {
+            private static final long serialVersionUID = 6503881346214855588L;
+
+            @Override
+            protected Object createEntry(String name) {
+                return new JmsQueue(name);
+            }
+        });
+
+        data.put("topic", new LazyCreateContext() {
+            private static final long serialVersionUID = 2019166796234979615L;
+
+            @Override
+            protected Object createEntry(String name) {
+                return new JmsTopic(name);
+            }
+        });
+
+        return createContext(environment, data);
+    }
+
+    static private String getValue(Hashtable environment, String key, String defaultValue) {
+        Object o = environment.get(key);
+        if (o != null && o instanceof String) {
+            return (String) o;
+        } else {
+            return defaultValue;
+        }
+    }
+
+    // Implementation methods
+    // -------------------------------------------------------------------------
+
+    protected ReadOnlyContext createContext(Hashtable environment, Map<String, Object> data) {
+        return new ReadOnlyContext(environment, data);
+    }
+
+    protected JmsConnectionFactory createConnectionFactory(String name, Hashtable environment) throws URISyntaxException {
+        Hashtable temp = new Hashtable(environment);
+        String prefix = connectionPrefix + name + ".";
+        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = (String) entry.getKey();
+            if (key.startsWith(prefix)) {
+                // Rename the key...
+                temp.remove(key);
+                key = key.substring(prefix.length());
+                temp.put(key, entry.getValue());
+            }
+        }
+        return createConnectionFactory(temp);
+    }
+
+    protected String[] getConnectionFactoryNames(Map environment) {
+        String factoryNames = (String) environment.get("factories");
+        if (factoryNames != null) {
+            List<String> list = new ArrayList<String>();
+            for (StringTokenizer enumeration = new StringTokenizer(factoryNames, ","); enumeration.hasMoreTokens();) {
+                list.add(enumeration.nextToken().trim());
+            }
+            int size = list.size();
+            if (size > 0) {
+                String[] answer = new String[size];
+                list.toArray(answer);
+                return answer;
+            }
+        }
+        return DEFAULT_CONNECTION_FACTORY_NAMES;
+    }
+
+    /**
+     * Factory method to create new Queue instances
+     */
+    protected Queue createQueue(String name) {
+        return new JmsQueue(name);
+    }
+
+    /**
+     * Factory method to create new Topic instances
+     */
+    protected Topic createTopic(String name) {
+        return new JmsTopic(name);
+    }
+
+    /**
+     * Factory method to create a new connection factory from the given
+     * environment
+     */
+    protected JmsConnectionFactory createConnectionFactory(Hashtable environment) throws URISyntaxException {
+        JmsConnectionFactory answer = new JmsConnectionFactory();
+        Properties properties = new Properties();
+        environment.remove("java.naming.factory.initial");
+        Object o = environment.remove("java.naming.provider.url");
+        if (o != null) {
+            answer.setBrokerURI(o.toString());
+        }
+        o = environment.remove("java.naming.security.principal");
+        if (o != null) {
+            answer.setUsername(o.toString());
+        }
+        o = environment.remove("java.naming.security.credentials");
+        if (o != null) {
+            answer.setPassword(o.toString());
+        }
+        properties.putAll(environment);
+        answer.setProperties(properties);
+        return answer;
+    }
+
+    public String getConnectionPrefix() {
+        return connectionPrefix;
+    }
+
+    public void setConnectionPrefix(String connectionPrefix) {
+        this.connectionPrefix = connectionPrefix;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java
new file mode 100644
index 0000000..11b52fe
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java
@@ -0,0 +1,46 @@
+/**
+ * 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.jms.jndi;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+/**
+ * Allows users to dynamically create items
+ *
+ * @since 1.0
+ */
+public abstract class LazyCreateContext extends ReadOnlyContext {
+
+    private static final long serialVersionUID = 5131341840091473967L;
+
+    @Override
+    public Object lookup(String name) throws NamingException {
+        try {
+            return super.lookup(name);
+        } catch (NameNotFoundException e) {
+            Object answer = createEntry(name);
+            if (answer == null) {
+                throw e;
+            }
+            internalBind(name, answer);
+            return answer;
+        }
+    }
+
+    protected abstract Object createEntry(String name);
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java
new file mode 100644
index 0000000..abdd4a2
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java
@@ -0,0 +1,35 @@
+/**
+ * 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.jms.jndi;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+
+/**
+ * A default implementation of {@link NameParser}
+ *
+ * @since 1.0
+ */
+public class NameParserImpl implements NameParser {
+
+    @Override
+    public Name parse(String name) throws NamingException {
+        return new CompositeName(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java
new file mode 100644
index 0000000..60181d1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java
@@ -0,0 +1,465 @@
+/**
+ * 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.jms.jndi;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.naming.Binding;
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.LinkRef;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NotContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
+import javax.naming.spi.NamingManager;
+
+/**
+ * A read-only Context
+ * <p/>
+ * This version assumes it and all its sub-context are read-only and any attempt
+ * to modify (e.g. through bind) will result in an
+ * OperationNotSupportedException. Each Context in the tree builds a cache of
+ * the entries in all sub-contexts to optimize the performance of lookup.
+ * </p>
+ * <p>
+ * This implementation is intended to optimize the performance of lookup(String)
+ * to about the level of a HashMap get. It has been observed that the scheme
+ * resolution phase performed by the JVM takes considerably longer, so for
+ * optimum performance lookups should be coded like:
+ * </p>
+ * <code>
+ * Context componentContext = (Context)new InitialContext().lookup("java:comp");
+ * String envEntry = (String) componentContext.lookup("env/myEntry");
+ * String envEntry2 = (String) componentContext.lookup("env/myEntry2");
+ * </code>
+ */
+@SuppressWarnings("unchecked")
+public class ReadOnlyContext implements Context, Serializable {
+
+    public static final String SEPARATOR = "/";
+    protected static final NameParser NAME_PARSER = new NameParserImpl();
+    private static final long serialVersionUID = -5754338187296859149L;
+
+    protected final Hashtable<String, Object> environment; // environment for this context
+    protected final Map<String, Object> bindings; // bindings at my level
+    protected final Map<String, Object> treeBindings; // all bindings under me
+
+    private boolean frozen;
+    private String nameInNamespace = "";
+
+    public ReadOnlyContext() {
+        environment = new Hashtable<String, Object>();
+        bindings = new HashMap<String, Object>();
+        treeBindings = new HashMap<String, Object>();
+    }
+
+    public ReadOnlyContext(Hashtable env) {
+        if (env == null) {
+            this.environment = new Hashtable<String, Object>();
+        } else {
+            this.environment = new Hashtable<String, Object>(env);
+        }
+        this.bindings = Collections.EMPTY_MAP;
+        this.treeBindings = Collections.EMPTY_MAP;
+    }
+
+    public ReadOnlyContext(Hashtable environment, Map<String, Object> bindings) {
+        if (environment == null) {
+            this.environment = new Hashtable<String, Object>();
+        } else {
+            this.environment = new Hashtable<String, Object>(environment);
+        }
+        this.bindings = new HashMap<String, Object>();
+        treeBindings = new HashMap<String, Object>();
+        if (bindings != null) {
+            for (Map.Entry<String, Object> binding : bindings.entrySet()) {
+                try {
+                    internalBind(binding.getKey(), binding.getValue());
+                } catch (Throwable e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        frozen = true;
+    }
+
+    public ReadOnlyContext(Hashtable environment, Map bindings, String nameInNamespace) {
+        this(environment, bindings);
+        this.nameInNamespace = nameInNamespace;
+    }
+
+    protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env) {
+        this.bindings = clone.bindings;
+        this.treeBindings = clone.treeBindings;
+        this.environment = new Hashtable<String, Object>(env);
+    }
+
+    protected ReadOnlyContext(ReadOnlyContext clone, Hashtable<String, Object> env, String nameInNamespace) {
+        this(clone, env);
+        this.nameInNamespace = nameInNamespace;
+    }
+
+    public void freeze() {
+        frozen = true;
+    }
+
+    boolean isFrozen() {
+        return frozen;
+    }
+
+    /**
+     * internalBind is intended for use only during setup or possibly by
+     * suitably synchronized super-classes. It binds every possible lookup into a
+     * map in each context. To do this, each context strips off one name segment
+     * and if necessary creates a new context for it. Then it asks that context
+     * to bind the remaining name. It returns a map containing all the bindings
+     * from the next context, plus the context it just created (if it in fact
+     * created it). (the names are suitably extended by the segment originally
+     * lopped off).
+     *
+     * @param name
+     * @param value
+     * @return
+     * @throws javax.naming.NamingException
+     */
+    protected Map<String, Object> internalBind(String name, Object value) throws NamingException {
+        assert name != null && name.length() > 0;
+        assert !frozen;
+
+        Map<String, Object> newBindings = new HashMap<String, Object>();
+        int pos = name.indexOf('/');
+        if (pos == -1) {
+            if (treeBindings.put(name, value) != null) {
+                throw new NamingException("Something already bound at " + name);
+            }
+            bindings.put(name, value);
+            newBindings.put(name, value);
+        } else {
+            String segment = name.substring(0, pos);
+            assert segment != null;
+            assert !segment.equals("");
+            Object o = treeBindings.get(segment);
+            if (o == null) {
+                o = newContext();
+                treeBindings.put(segment, o);
+                bindings.put(segment, o);
+                newBindings.put(segment, o);
+            } else if (!(o instanceof ReadOnlyContext)) {
+                throw new NamingException("Something already bound where a subcontext should go");
+            }
+            ReadOnlyContext readOnlyContext = (ReadOnlyContext) o;
+            String remainder = name.substring(pos + 1);
+            Map<String, Object> subBindings = readOnlyContext.internalBind(remainder, value);
+            for (Iterator iterator = subBindings.entrySet().iterator(); iterator.hasNext();) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                String subName = segment + "/" + (String) entry.getKey();
+                Object bound = entry.getValue();
+                treeBindings.put(subName, bound);
+                newBindings.put(subName, bound);
+            }
+        }
+        return newBindings;
+    }
+
+    protected ReadOnlyContext newContext() {
+        return new ReadOnlyContext();
+    }
+
+    @Override
+    public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+        return environment.put(propName, propVal);
+    }
+
+    @Override
+    public Hashtable<String, Object> getEnvironment() throws NamingException {
+        return (Hashtable<String, Object>) environment.clone();
+    }
+
+    @Override
+    public Object removeFromEnvironment(String propName) throws NamingException {
+        return environment.remove(propName);
+    }
+
+    @Override
+    public Object lookup(String name) throws NamingException {
+        if (name.length() == 0) {
+            return this;
+        }
+        Object result = treeBindings.get(name);
+        if (result == null) {
+            result = bindings.get(name);
+        }
+        if (result == null) {
+            int pos = name.indexOf(':');
+            if (pos > 0) {
+                String scheme = name.substring(0, pos);
+                Context ctx = NamingManager.getURLContext(scheme, environment);
+                if (ctx == null) {
+                    throw new NamingException("scheme " + scheme + " not recognized");
+                }
+                return ctx.lookup(name);
+            } else {
+                // Split out the first name of the path
+                // and look for it in the bindings map.
+                CompositeName path = new CompositeName(name);
+
+                if (path.size() == 0) {
+                    return this;
+                } else {
+                    String first = path.get(0);
+                    Object obj = bindings.get(first);
+                    if (obj == null) {
+                        throw new NameNotFoundException(name);
+                    } else if (obj instanceof Context && path.size() > 1) {
+                        Context subContext = (Context) obj;
+                        obj = subContext.lookup(path.getSuffix(1));
+                    }
+                    return obj;
+                }
+            }
+        }
+        if (result instanceof LinkRef) {
+            LinkRef ref = (LinkRef) result;
+            result = lookup(ref.getLinkName());
+        }
+        if (result instanceof Reference) {
+            try {
+                result = NamingManager.getObjectInstance(result, null, null, this.environment);
+            } catch (NamingException e) {
+                throw e;
+            } catch (Exception e) {
+                throw (NamingException) new NamingException("could not look up : " + name).initCause(e);
+            }
+        }
+        if (result instanceof ReadOnlyContext) {
+            String prefix = getNameInNamespace();
+            if (prefix.length() > 0) {
+                prefix = prefix + SEPARATOR;
+            }
+            result = new ReadOnlyContext((ReadOnlyContext) result, environment, prefix + name);
+        }
+        return result;
+    }
+
+    @Override
+    public Object lookup(Name name) throws NamingException {
+        return lookup(name.toString());
+    }
+
+    @Override
+    public Object lookupLink(String name) throws NamingException {
+        return lookup(name);
+    }
+
+    @Override
+    public Name composeName(Name name, Name prefix) throws NamingException {
+        Name result = (Name) prefix.clone();
+        result.addAll(name);
+        return result;
+    }
+
+    @Override
+    public String composeName(String name, String prefix) throws NamingException {
+        CompositeName result = new CompositeName(prefix);
+        result.addAll(new CompositeName(name));
+        return result.toString();
+    }
+
+    @Override
+    public NamingEnumeration list(String name) throws NamingException {
+        Object o = lookup(name);
+        if (o == this) {
+            return new ListEnumeration();
+        } else if (o instanceof Context) {
+            return ((Context) o).list("");
+        } else {
+            throw new NotContextException();
+        }
+    }
+
+    @Override
+    public NamingEnumeration listBindings(String name) throws NamingException {
+        Object o = lookup(name);
+        if (o == this) {
+            return new ListBindingEnumeration();
+        } else if (o instanceof Context) {
+            return ((Context) o).listBindings("");
+        } else {
+            throw new NotContextException();
+        }
+    }
+
+    @Override
+    public Object lookupLink(Name name) throws NamingException {
+        return lookupLink(name.toString());
+    }
+
+    @Override
+    public NamingEnumeration list(Name name) throws NamingException {
+        return list(name.toString());
+    }
+
+    @Override
+    public NamingEnumeration listBindings(Name name) throws NamingException {
+        return listBindings(name.toString());
+    }
+
+    @Override
+    public void bind(Name name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void bind(String name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void close() throws NamingException {
+        // ignore
+    }
+
+    @Override
+    public Context createSubcontext(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public Context createSubcontext(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void destroySubcontext(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void destroySubcontext(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public String getNameInNamespace() throws NamingException {
+        return nameInNamespace;
+    }
+
+    @Override
+    public NameParser getNameParser(Name name) throws NamingException {
+        return NAME_PARSER;
+    }
+
+    @Override
+    public NameParser getNameParser(String name) throws NamingException {
+        return NAME_PARSER;
+    }
+
+    @Override
+    public void rebind(Name name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void rebind(String name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void rename(Name oldName, Name newName) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void rename(String oldName, String newName) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void unbind(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void unbind(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    private abstract class LocalNamingEnumeration implements NamingEnumeration {
+        private final Iterator i = bindings.entrySet().iterator();
+
+        @Override
+        public boolean hasMore() throws NamingException {
+            return i.hasNext();
+        }
+
+        @Override
+        public boolean hasMoreElements() {
+            return i.hasNext();
+        }
+
+        protected Map.Entry getNext() {
+            return (Map.Entry) i.next();
+        }
+
+        @Override
+        public void close() throws NamingException {
+        }
+    }
+
+    private class ListEnumeration extends LocalNamingEnumeration {
+        ListEnumeration() {
+        }
+
+        @Override
+        public Object next() throws NamingException {
+            return nextElement();
+        }
+
+        @Override
+        public Object nextElement() {
+            Map.Entry entry = getNext();
+            return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName());
+        }
+    }
+
+    private class ListBindingEnumeration extends LocalNamingEnumeration {
+        ListBindingEnumeration() {
+        }
+
+        @Override
+        public Object next() throws NamingException {
+            return nextElement();
+        }
+
+        @Override
+        public Object nextElement() {
+            Map.Entry entry = getNext();
+            return new Binding((String) entry.getKey(), entry.getValue());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java
new file mode 100644
index 0000000..2383768
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java
@@ -0,0 +1,831 @@
+/**
+ * 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.jms.message;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.facade.JmsBytesMessageFacade;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtbuf.ByteArrayInputStream;
+import org.fusesource.hawtbuf.DataByteArrayOutputStream;
+
+/**
+ * A <CODE>BytesMessage</CODE> object is used to send a message containing a
+ * stream of uninterpreted bytes. It inherits from the <CODE>Message</CODE>
+ * interface and adds a bytes message body. The receiver of the message supplies
+ * the interpretation of the bytes.
+ * <p/>
+ * The <CODE>BytesMessage</CODE> methods are based largely on those found in
+ * <CODE>java.io.DataInputStream</CODE> and
+ * <CODE>java.io.DataOutputStream</CODE>.
+ * <p/>
+ * This message type is for client encoding of existing message formats. If
+ * possible, one of the other self-defining message types should be used
+ * instead.
+ * <p/>
+ * Although the JMS API allows the use of message properties with byte messages,
+ * they are typically not used, since the inclusion of properties may affect the
+ * format.
+ * <p/>
+ * The primitive types can be written explicitly using methods for each type.
+ * They may also be written generically as objects. For instance, a call to
+ * <CODE>BytesMessage.writeInt(6)</CODE> is equivalent to
+ * <CODE> BytesMessage.writeObject(new Integer(6))</CODE>. Both forms are
+ * provided, because the explicit form is convenient for static programming, and
+ * the object form is needed when types are not known at compile time.
+ * <p/>
+ * When the message is first created, and when <CODE>clearBody</CODE> is
+ * called, the body of the message is in write-only mode. After the first call
+ * to <CODE>reset</CODE> has been made, the message body is in read-only mode.
+ * After a message has been sent, the client that sent it can retain and modify
+ * it without affecting the message that has been sent. The same message object
+ * can be sent multiple times. When a message has been received, the provider
+ * has called <CODE>reset</CODE> so that the message body is in read-only mode
+ * for the client.
+ * <p/>
+ * If <CODE>clearBody</CODE> is called on a message in read-only mode, the
+ * message body is cleared and the message is in write-only mode.
+ * <p/>
+ * If a client attempts to read a message in write-only mode, a
+ * <CODE>MessageNotReadableException</CODE> is thrown.
+ * <p/>
+ * If a client attempts to write a message in read-only mode, a
+ * <CODE>MessageNotWriteableException</CODE> is thrown.
+ *
+ * @see javax.jms.Session#createBytesMessage()
+ * @see javax.jms.MapMessage
+ * @see javax.jms.Message
+ * @see javax.jms.ObjectMessage
+ * @see javax.jms.StreamMessage
+ * @see javax.jms.TextMessage
+ */
+public class JmsBytesMessage extends JmsMessage implements BytesMessage {
+
+    protected transient DataByteArrayOutputStream bytesOut;
+    protected transient DataInputStream dataIn;
+    protected transient int length;
+
+    private final JmsBytesMessageFacade facade;
+
+    public JmsBytesMessage(JmsBytesMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsBytesMessage copy() throws JMSException {
+        storeContent();
+        JmsBytesMessage other = new JmsBytesMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    private void copy(JmsBytesMessage other) throws JMSException {
+        super.copy(other);
+        this.bytesOut = null;
+        this.dataIn = null;
+    }
+
+    @Override
+    public void onSend() throws JMSException {
+        this.storeContent();
+        super.onSend();
+    }
+
+    /**
+     * Clears out the message body. Clearing a message's body does not clear its
+     * header values or property entries.
+     * <p/>
+     * If this message body was read-only, calling this method leaves the
+     * message body in the same state as an empty body in a newly created
+     * message.
+     *
+     * @throws JMSException if the JMS provider fails to clear the message body
+     *                      due to some internal error.
+     */
+    @Override
+    public void clearBody() throws JMSException {
+        super.clearBody();
+        this.dataIn = null;
+        this.bytesOut = null;
+    }
+
+    /**
+     * Gets the number of bytes of the message body when the message is in
+     * read-only mode. The value returned can be used to allocate a byte array.
+     * The value returned is the entire length of the message body, regardless
+     * of where the pointer for reading the message is currently located.
+     *
+     * @return number of bytes in the message
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     * @since 1.1
+     */
+
+    @Override
+    public long getBodyLength() throws JMSException {
+        initializeReading();
+        return length;
+    }
+
+    /**
+     * Reads a <code>boolean</code> from the bytes message stream.
+     *
+     * @return the <code>boolean</code> value read
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public boolean readBoolean() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readBoolean();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 8-bit value from the bytes message stream.
+     *
+     * @return the next byte from the bytes message stream as a signed 8-bit
+     *         <code>byte</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public byte readByte() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readByte();
+        } catch (EOFException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    /**
+     * Reads an unsigned 8-bit number from the bytes message stream.
+     *
+     * @return the next byte from the bytes message stream, interpreted as an
+     *         unsigned 8-bit number
+     * @throws JMSException                  if the JMS provider fails to read the message due to
+     *                                       some internal error.
+     * @throws javax.jms.MessageEOFException if unexpected end of bytes stream has been
+     *                                       reached.
+     * @throws MessageNotReadableException   if the message is in write-only mode.
+     */
+    @Override
+    public int readUnsignedByte() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readUnsignedByte();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 16-bit number from the bytes message stream.
+     *
+     * @return the next two bytes from the bytes message stream, interpreted as
+     *         a signed 16-bit number
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public short readShort() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readShort();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads an unsigned 16-bit number from the bytes message stream.
+     *
+     * @return the next two bytes from the bytes message stream, interpreted as
+     *         an unsigned 16-bit integer
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readUnsignedShort() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readUnsignedShort();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a Unicode character value from the bytes message stream.
+     *
+     * @return the next two bytes from the bytes message stream as a Unicode
+     *         character
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public char readChar() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readChar();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 32-bit integer from the bytes message stream.
+     *
+     * @return the next four bytes from the bytes message stream, interpreted as
+     *         an <code>int</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readInt() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readInt();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 64-bit integer from the bytes message stream.
+     *
+     * @return the next eight bytes from the bytes message stream, interpreted
+     *         as a <code>long</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public long readLong() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readLong();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a <code>float</code> from the bytes message stream.
+     *
+     * @return the next four bytes from the bytes message stream, interpreted as
+     *         a <code>float</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public float readFloat() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readFloat();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a <code>double</code> from the bytes message stream.
+     *
+     * @return the next eight bytes from the bytes message stream, interpreted
+     *         as a <code>double</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public double readDouble() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readDouble();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a string that has been encoded using a modified UTF-8 format from
+     * the bytes message stream.
+     * <p/>
+     * For more information on the UTF-8 format, see "File System Safe UCS
+     * Transformation Format (FSS_UTF)", X/Open Preliminary Specification,
+     * X/Open Company Ltd., Document Number: P316. This information also appears
+     * in ISO/IEC 10646, Annex P.
+     *
+     * @return a Unicode string from the bytes message stream
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public String readUTF() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readUTF();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a byte array from the bytes message stream.
+     * <p/>
+     * If the length of array <code>value</code> is less than the number of
+     * bytes remaining to be read from the stream, the array should be filled. A
+     * subsequent call reads the next increment, and so on.
+     * <p/>
+     * If the number of bytes remaining in the stream is less than the length of
+     * array <code>value</code>, the bytes should be read into the array. The
+     * return value of the total number of bytes read will be less than the
+     * length of the array, indicating that there are no more bytes left to be
+     * read from the stream. The next read of the stream returns -1.
+     *
+     * @param value the buffer into which the data is read
+     * @return the total number of bytes read into the buffer, or -1 if there is
+     *         no more data because the end of the stream has been reached
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readBytes(byte[] value) throws JMSException {
+        return readBytes(value, value.length);
+    }
+
+    /**
+     * Reads a portion of the bytes message stream.
+     * <p/>
+     * If the length of array <code>value</code> is less than the number of
+     * bytes remaining to be read from the stream, the array should be filled. A
+     * subsequent call reads the next increment, and so on.
+     * <p/>
+     * If the number of bytes remaining in the stream is less than the length of
+     * array <code>value</code>, the bytes should be read into the array. The
+     * return value of the total number of bytes read will be less than the
+     * length of the array, indicating that there are no more bytes left to be
+     * read from the stream. The next read of the stream returns -1. <p/> If
+     * <code>length</code> is negative, or <code>length</code> is greater
+     * than the length of the array <code>value</code>, then an
+     * <code>IndexOutOfBoundsException</code> is thrown. No bytes will be read
+     * from the stream for this exception case.
+     *
+     * @param value  the buffer into which the data is read
+     * @param length the number of bytes to read; must be less than or equal to
+     *               <code>value.length</code>
+     * @return the total number of bytes read into the buffer, or -1 if there is
+     *         no more data because the end of the stream has been reached
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readBytes(byte[] value, int length) throws JMSException {
+        initializeReading();
+
+        if (length < 0 || value.length < length) {
+            throw new IndexOutOfBoundsException(
+                "length must not be negative or larger than the size of the provided array");
+        }
+
+        try {
+            int n = 0;
+            while (n < length) {
+                int count = this.dataIn.read(value, n, length - n);
+                if (count < 0) {
+                    break;
+                }
+                n += count;
+            }
+            if (n == 0 && length > 0) {
+                n = -1;
+            }
+            return n;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>boolean</code> to the bytes message stream as a 1-byte
+     * value. The value <code>true</code> is written as the value
+     * <code>(byte)1</code>; the value <code>false</code> is written as the
+     * value <code>(byte)0</code>.
+     *
+     * @param value the <code>boolean</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeBoolean(boolean value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeBoolean(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>byte</code> to the bytes message stream as a 1-byte
+     * value.
+     *
+     * @param value the <code>byte</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeByte(byte value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeByte(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>short</code> to the bytes message stream as two bytes,
+     * high byte first.
+     *
+     * @param value the <code>short</code> to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeShort(short value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeShort(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>char</code> to the bytes message stream as a 2-byte
+     * value, high byte first.
+     *
+     * @param value the <code>char</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeChar(char value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeChar(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes an <code>int</code> to the bytes message stream as four bytes,
+     * high byte first.
+     *
+     * @param value the <code>int</code> to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeInt(int value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeInt(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>long</code> to the bytes message stream as eight bytes,
+     * high byte first.
+     *
+     * @param value the <code>long</code> to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeLong(long value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeLong(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Converts the <code>float</code> argument to an <code>int</code> using
+     * the <code>floatToIntBits</code> method in class <code>Float</code>,
+     * and then writes that <code>int</code> value to the bytes message stream
+     * as a 4-byte quantity, high byte first.
+     *
+     * @param value the <code>float</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeFloat(float value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeFloat(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Converts the <code>double</code> argument to a <code>long</code>
+     * using the <code>doubleToLongBits</code> method in class
+     * <code>Double</code>, and then writes that <code>long</code> value to
+     * the bytes message stream as an 8-byte quantity, high byte first.
+     *
+     * @param value the <code>double</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeDouble(double value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeDouble(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a string to the bytes message stream using UTF-8 encoding in a
+     * machine-independent manner.
+     * <p/>
+     * For more information on the UTF-8 format, see "File System Safe UCS
+     * Transformation Format (FSS_UTF)", X/Open Preliminary Specification,
+     * X/Open Company Ltd., Document Number: P316. This information also appears
+     * in ISO/IEC 10646, Annex P.
+     *
+     * @param value the <code>String</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeUTF(String value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeUTF(value);
+        } catch (IOException ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    /**
+     * Writes a byte array to the bytes message stream.
+     *
+     * @param value the byte array to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeBytes(byte[] value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.write(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a portion of a byte array to the bytes message stream.
+     *
+     * @param value  the byte array value to be written
+     * @param offset the initial offset within the byte array
+     * @param length the number of bytes to use
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeBytes(byte[] value, int offset, int length) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.write(value, offset, length);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes an object to the bytes message stream.
+     * <p/>
+     * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>,
+     * <code>Long</code> &nbsp;...), <code>String</code> objects, and byte
+     * arrays.
+     *
+     * @param value the object in the Java programming language ("Java object")
+     *              to be written; it must not be null
+     * @throws JMSException                   if the JMS provider fails to write the message due
+     *                                        to some internal error.
+     * @throws MessageFormatException         if the object is of an invalid type.
+     * @throws MessageNotWriteableException   if the message is in read-only mode.
+     * @throws java.lang.NullPointerException if the parameter
+     *                                        <code>value</code> is null.
+     */
+    @Override
+    public void writeObject(Object value) throws JMSException {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+        initializeWriting();
+        if (value instanceof Boolean) {
+            writeBoolean(((Boolean) value).booleanValue());
+        } else if (value instanceof Character) {
+            writeChar(((Character) value).charValue());
+        } else if (value instanceof Byte) {
+            writeByte(((Byte) value).byteValue());
+        } else if (value instanceof Short) {
+            writeShort(((Short) value).shortValue());
+        } else if (value instanceof Integer) {
+            writeInt(((Integer) value).intValue());
+        } else if (value instanceof Long) {
+            writeLong(((Long) value).longValue());
+        } else if (value instanceof Float) {
+            writeFloat(((Float) value).floatValue());
+        } else if (value instanceof Double) {
+            writeDouble(((Double) value).doubleValue());
+        } else if (value instanceof String) {
+            writeUTF(value.toString());
+        } else if (value instanceof byte[]) {
+            writeBytes((byte[]) value);
+        } else {
+            throw new MessageFormatException("Cannot write non-primitive type:" + value.getClass());
+        }
+    }
+
+    /**
+     * Puts the message body in read-only mode and repositions the stream of
+     * bytes to the beginning.
+     *
+     * @throws JMSException if an internal error occurs
+     */
+    @Override
+    public void reset() throws JMSException {
+        storeContent();
+        this.bytesOut = null;
+        this.dataIn = null;
+        setReadOnlyBody(true);
+    }
+
+    @Override
+    public void setObjectProperty(String name, Object value) throws JMSException {
+        initializeWriting();
+        super.setObjectProperty(name, value);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " JmsBytesMessage{ " + "bytesOut = " + bytesOut + ", dataIn = " + dataIn + " }";
+    }
+
+    /**
+     * Direct view of the underlying message contents.
+     *
+     * @return a Buffer holding the bytes contained in this message.
+     */
+    public Buffer getContent() {
+        return this.facade.getContent();
+    }
+
+    /**
+     * A direct write method to the underlying message content buffer.
+     *
+     * @param content
+     *        the new content to assign to this message.
+     */
+    public void setContent(Buffer content) {
+        this.facade.setContent(content);
+    }
+
+    private void initializeWriting() throws JMSException {
+        checkReadOnlyBody();
+        if (this.bytesOut == null) {
+            this.bytesOut = new DataByteArrayOutputStream();
+        }
+    }
+
+    private void initializeReading() throws JMSException {
+        checkWriteOnlyBody();
+        if (dataIn == null) {
+            Buffer buffer = facade.getContent();
+            if (buffer == null) {
+                buffer = new Buffer(0);
+            }
+            dataIn = new DataInputStream(new ByteArrayInputStream(buffer));
+            this.length = buffer.getLength();
+        }
+    }
+
+    private void storeContent() throws JMSException {
+        try {
+            if (bytesOut != null) {
+                bytesOut.close();
+                Buffer bs = bytesOut.toBuffer();
+                facade.setContent(bs);
+                bytesOut = null;
+            }
+        } catch (IOException ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java
new file mode 100644
index 0000000..c909f2d
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java
@@ -0,0 +1,94 @@
+/**
+ * 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.jms.message;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultBytesMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMapMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultObjectMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultStreamMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultTextMessageFacade;
+
+/**
+ * Default implementation of the ProviderMessageFactory that create simple
+ * generic javax.jms.Message types that can be sent to any Provider instance.
+ *
+ * TODO: Once the AMQP Message Facade stuff is done we should move this factory
+ *       and the default JmsMessageFacade implementations into the test package
+ *       since their primary use will be to test the JMS spec compliance of the
+ *       JmsMessage classes.
+ */
+public class JmsDefaultMessageFactory implements JmsMessageFactory {
+
+    @Override
+    public JmsMessage createMessage() throws UnsupportedOperationException {
+        return new JmsMessage(new JmsDefaultMessageFacade());
+    }
+
+    @Override
+    public JmsTextMessage createTextMessage() throws UnsupportedOperationException {
+        return createTextMessage(null);
+    }
+
+    @Override
+    public JmsTextMessage createTextMessage(String payload) throws UnsupportedOperationException {
+        JmsTextMessage result = new JmsTextMessage(new JmsDefaultTextMessageFacade());
+        if (payload != null) {
+            try {
+                result.setText(payload);
+            } catch (JMSException e) {
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public JmsBytesMessage createBytesMessage() throws UnsupportedOperationException {
+        return new JmsBytesMessage(new JmsDefaultBytesMessageFacade());
+    }
+
+    @Override
+    public JmsMapMessage createMapMessage() throws UnsupportedOperationException {
+        return new JmsMapMessage(new JmsDefaultMapMessageFacade());
+    }
+
+    @Override
+    public JmsStreamMessage createStreamMessage() throws UnsupportedOperationException {
+        return new JmsStreamMessage(new JmsDefaultStreamMessageFacade());
+    }
+
+    @Override
+    public JmsObjectMessage createObjectMessage() throws UnsupportedOperationException {
+        return createObjectMessage(null);
+    }
+
+    @Override
+    public JmsObjectMessage createObjectMessage(Serializable payload) throws UnsupportedOperationException {
+        JmsObjectMessage result = new JmsObjectMessage(new JmsDefaultObjectMessageFacade());
+        if (payload != null) {
+            try {
+                result.setObject(payload);
+            } catch (Exception e) {
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java
new file mode 100644
index 0000000..e651060
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java
@@ -0,0 +1,57 @@
+/**
+ * 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.jms.message;
+
+import org.apache.qpid.jms.meta.JmsConsumerId;
+
+/**
+ * Envelope used to deliver incoming messages to their targeted consumer.
+ */
+public class JmsInboundMessageDispatch {
+
+    private JmsConsumerId consumerId;
+    private JmsMessage message;
+    private Object providerHint;
+
+    public JmsMessage getMessage() {
+        return message;
+    }
+
+    public void setMessage(JmsMessage message) {
+        this.message = message;
+    }
+
+    public JmsConsumerId getConsumerId() {
+        return consumerId;
+    }
+
+    public void setConsumerId(JmsConsumerId consumerId) {
+        this.consumerId = consumerId;
+    }
+
+    public Object getProviderHint() {
+        return this.providerHint;
+    }
+
+    public void setProviderHint(Object hint) {
+        this.providerHint = hint;
+    }
+
+    public void onMessageRedelivered() {
+        this.message.incrementRedeliveryCount();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java
new file mode 100644
index 0000000..9414eca
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java
@@ -0,0 +1,320 @@
+/**
+ * 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.jms.message;
+
+import java.util.Enumeration;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.MessageFormatException;
+
+import org.apache.qpid.jms.message.facade.JmsMapMessageFacade;
+
+/**
+ * Implementation of the JMS MapMessage.
+ */
+public class JmsMapMessage extends JmsMessage implements MapMessage {
+
+    JmsMapMessageFacade facade;
+
+    public JmsMapMessage(JmsMapMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsMapMessage copy() throws JMSException {
+        JmsMapMessage other = new JmsMapMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    @Override
+    public void clearBody() throws JMSException {
+        super.clearBody();
+        facade.clearBody();
+    }
+
+    @Override
+    public boolean getBoolean(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Boolean) {
+            return ((Boolean) value).booleanValue();
+        } else if (value instanceof String || value == null) {
+            return Boolean.valueOf((String) value).booleanValue();
+        } else {
+            throw new MessageFormatException("Cannot read a boolean from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public byte getByte(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Byte) {
+            return ((Byte) value).byteValue();
+        } else if (value instanceof String || value == null) {
+            return Byte.valueOf((String) value).byteValue();
+        } else {
+            throw new MessageFormatException("Cannot read a byte from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public short getShort(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Short) {
+            return ((Short) value).shortValue();
+        } else if (value instanceof Byte) {
+            return ((Byte) value).shortValue();
+        } else if (value instanceof String || value == null) {
+            return Short.valueOf((String) value).shortValue();
+        } else {
+            throw new MessageFormatException("Cannot read a short from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public char getChar(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value == null) {
+            throw new NullPointerException();
+        } else if (value instanceof Character) {
+            return ((Character) value).charValue();
+        } else {
+            throw new MessageFormatException("Cannot read a short from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public int getInt(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Integer) {
+            return ((Integer) value).intValue();
+        } else if (value instanceof Short) {
+            return ((Short) value).intValue();
+        } else if (value instanceof Byte) {
+            return ((Byte) value).intValue();
+        } else if (value instanceof String || value == null) {
+            return Integer.valueOf((String) value).intValue();
+        } else {
+            throw new MessageFormatException("Cannot read an int from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public long getLong(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Long) {
+            return ((Long) value).longValue();
+        } else if (value instanceof Integer) {
+            return ((Integer) value).longValue();
+        } else if (value instanceof Short) {
+            return ((Short) value).longValue();
+        } else if (value instanceof Byte) {
+            return ((Byte) value).longValue();
+        } else if (value instanceof String || value == null) {
+            return Long.valueOf((String) value).longValue();
+        } else {
+            throw new MessageFormatException("Cannot read a long from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public float getFloat(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Float) {
+            return ((Float) value).floatValue();
+        } else if (value instanceof String || value == null) {
+            return Float.valueOf((String) value).floatValue();
+        } else {
+            throw new MessageFormatException("Cannot read a float from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public double getDouble(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Double) {
+            return ((Double) value).doubleValue();
+        } else if (value instanceof Float) {
+            return ((Float) value).floatValue();
+        } else if (value instanceof String || value == null) {
+            return Double.valueOf((String) value).doubleValue();
+        } else {
+            throw new MessageFormatException("Cannot read a double from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public String getString(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value == null) {
+            return null;
+        } else if (value instanceof byte[]) {
+            throw new MessageFormatException("Use getBytes to read a byte array");
+        } else {
+            return value.toString();
+        }
+    }
+
+    @Override
+    public byte[] getBytes(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value == null) {
+            return (byte[]) value;
+        } else if (value instanceof byte[]) {
+            byte[] original = (byte[]) value;
+            byte[] clone = new byte[original.length];
+            System.arraycopy(original, 0, clone, 0, original.length);
+            return clone;
+        } else {
+            throw new MessageFormatException("Cannot read a byte[] from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public Object getObject(String name) throws JMSException {
+        checkKeyNameIsValid(name);
+        return facade.get(name);
+    }
+
+    @Override
+    public Enumeration<String> getMapNames() throws JMSException {
+        return facade.getMapNames();
+    }
+
+    @Override
+    public void setBoolean(String name, boolean value) throws JMSException {
+        put(name, value ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    @Override
+    public void setByte(String name, byte value) throws JMSException {
+        put(name, Byte.valueOf(value));
+    }
+
+    @Override
+    public void setShort(String name, short value) throws JMSException {
+        put(name, Short.valueOf(value));
+    }
+
+    @Override
+    public void setChar(String name, char value) throws JMSException {
+        put(name, Character.valueOf(value));
+    }
+
+    @Override
+    public void setInt(String name, int value) throws JMSException {
+        put(name, Integer.valueOf(value));
+    }
+
+    @Override
+    public void setLong(String name, long value) throws JMSException {
+        put(name, Long.valueOf(value));
+    }
+
+    @Override
+    public void setFloat(String name, float value) throws JMSException {
+        checkReadOnlyBody();
+        put(name, new Float(value));
+    }
+
+    @Override
+    public void setDouble(String name, double value) throws JMSException {
+        put(name, new Double(value));
+    }
+
+    @Override
+    public void setString(String name, String value) throws JMSException {
+        put(name, value);
+    }
+
+    @Override
+    public void setBytes(String name, byte[] value) throws JMSException {
+        setBytes(name, value, 0, (value != null ? value.length : 0));
+    }
+
+    @Override
+    public void setBytes(String name, byte[] value, int offset, int length) throws JMSException {
+        // Fail early to avoid unnecessary array copy.
+        checkReadOnlyBody();
+        checkKeyNameIsValid(name);
+
+        byte[] clone = null;
+        if (value != null) {
+            clone = new byte[length];
+            System.arraycopy(value, offset, clone, 0, length);
+        }
+
+        put(name, clone);
+    }
+
+    @Override
+    public void setObject(String name, Object value) throws JMSException {
+        // byte[] not allowed on properties so cover that here.
+        if (!(value instanceof byte[])) {
+            checkValidObject(value);
+        }
+
+        put(name, value);
+    }
+
+    /**
+     * Indicates whether an item exists in this <CODE>MapMessage</CODE> object.
+     *
+     * @param name
+     *        the name of the item to test
+     * @return true if the item exists
+     * @throws JMSException
+     *         if the JMS provider fails to determine if the item exists due to
+     *         some internal error.
+     */
+    @Override
+    public boolean itemExists(String name) throws JMSException {
+        return facade.itemExists(name);
+    }
+
+    @Override
+    public String toString() {
+        // TODO - better toString implementation.
+        return "JmsMapMessage{ }";
+    }
+
+    private void put(String name, Object value) throws JMSException {
+        checkReadOnlyBody();
+        checkKeyNameIsValid(name);
+        facade.put(name, value);
+    }
+
+    private void checkKeyNameIsValid(String name) throws IllegalArgumentException {
+        if (name == null) {
+            throw new IllegalArgumentException("Map key name must not be null");
+        } else if (name.length() == 0) {
+            throw new IllegalArgumentException("Map key name must not be the empty string");
+        }
+    }
+}


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


[09/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/CompositeAmqpPeerRunnable.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/CompositeAmqpPeerRunnable.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/CompositeAmqpPeerRunnable.java
new file mode 100644
index 0000000..8839068
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/CompositeAmqpPeerRunnable.java
@@ -0,0 +1,49 @@
+/*
+ *
+ * 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.jms.test.testpeer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CompositeAmqpPeerRunnable implements AmqpPeerRunnable
+{
+    private List<AmqpPeerRunnable> _list = new ArrayList<AmqpPeerRunnable>();
+
+    public CompositeAmqpPeerRunnable(AmqpPeerRunnable... amqpPeerRunnables)
+    {
+        _list.addAll(Arrays.asList(amqpPeerRunnables));
+    }
+
+    public void add(AmqpPeerRunnable amqpPeerRunnable)
+    {
+        _list.add(amqpPeerRunnable);
+    }
+
+    @Override
+    public void run()
+    {
+        for(AmqpPeerRunnable r : _list)
+        {
+            r.run();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/DescriptorMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/DescriptorMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/DescriptorMatcher.java
new file mode 100644
index 0000000..c4d70e0
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/DescriptorMatcher.java
@@ -0,0 +1,53 @@
+/*
+ * 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.jms.test.testpeer;
+
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+public class DescriptorMatcher extends TypeSafeMatcher<DescribedType>
+{
+    private final UnsignedLong _expectedDescriptorCode;
+    private final Symbol _expectedDescriptorSymbol;
+
+    public DescriptorMatcher(UnsignedLong expectedDescriptorCode, Symbol expectedDescriptorSymbol)
+    {
+        _expectedDescriptorCode = expectedDescriptorCode;
+        _expectedDescriptorSymbol = expectedDescriptorSymbol;
+    }
+
+    @Override
+    public void describeTo(Description description)
+    {
+        description.appendText("A described type with descriptor that is either symbol ")
+            .appendValue(_expectedDescriptorSymbol)
+            .appendText(" or code ")
+            .appendValue(_expectedDescriptorCode);
+    }
+
+    @Override
+    protected boolean matchesSafely(DescribedType dt)
+    {
+        return _expectedDescriptorCode.equals(dt.getDescriptor()) || _expectedDescriptorSymbol.equals(dt.getDescriptor());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameHandler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameHandler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameHandler.java
new file mode 100644
index 0000000..c188dc2
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameHandler.java
@@ -0,0 +1,27 @@
+/*
+ * 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.jms.test.testpeer;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+
+interface FrameHandler extends Handler
+{
+    void frame(int type, int channel, DescribedType describedType, Binary payload, TestAmqpPeer peer);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameMatchingHandler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameMatchingHandler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameMatchingHandler.java
new file mode 100644
index 0000000..5ccabcb
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameMatchingHandler.java
@@ -0,0 +1,146 @@
+/*
+ * 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.jms.test.testpeer;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class FrameMatchingHandler implements FrameHandler
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(FrameMatchingHandler.class);
+
+    public static int ANY_CHANNEL = -1;
+
+    private final UnsignedLong _numericDescriptor;
+    private final Symbol _symbolicDescriptor;
+    private final FrameType _frameType;
+
+    /** The expected channel number, or {@link #ANY_CHANNEL} if we don't care */
+    private int _expectedChannel;
+    private int _actualChannel;
+
+    private Runnable _onSuccessAction;
+    private volatile boolean _isComplete;
+
+    protected FrameMatchingHandler(FrameType frameType,
+                                   int channel,
+                                   UnsignedLong numericDescriptor,
+                                   Symbol symbolicDescriptor, Runnable onSuccessAction)
+    {
+        _frameType = frameType;
+        _numericDescriptor = numericDescriptor;
+        _symbolicDescriptor = symbolicDescriptor;
+        _expectedChannel = channel;
+        _onSuccessAction = onSuccessAction;
+    }
+
+    protected abstract Map<Enum<?>,Object> getReceivedFields();
+
+    /**
+     * Handle the supplied frame and its payload, e.g. by checking that it matches what we expect
+     * @throws RuntimeException or a subclass thereof if the frame does not match what we expect
+     */
+    protected abstract void verifyFrame(List<Object> described, Binary payload);
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void frame(int type, int ch, DescribedType dt, Binary payload, TestAmqpPeer peer)
+    {
+        if(type == _frameType.ordinal()
+           && (_expectedChannel == ANY_CHANNEL || _expectedChannel == ch)
+           && (_numericDescriptor.equals(dt.getDescriptor()) || _symbolicDescriptor.equals(dt.getDescriptor()))
+           && (dt.getDescribed() instanceof List))
+        {
+            _actualChannel = ch;
+            verifyFrame((List<Object>)dt.getDescribed(),payload);
+            succeeded();
+        }
+        else
+        {
+            throw new IllegalArgumentException(String.format(
+                    "Frame was not as expected. Expected: " +
+                    "type=%s, channel=%s, descriptor=%s/%s but got: " +
+                    "type=%s, channel=%s, descriptor=%s",
+                    _frameType.ordinal(), expectedChannelString(), _symbolicDescriptor, _numericDescriptor,
+                    type, ch, dt.getDescriptor()));
+        }
+    }
+
+    private String expectedChannelString()
+    {
+        return _expectedChannel == ANY_CHANNEL ? "<any>" : String.valueOf(_expectedChannel);
+    }
+
+    private void succeeded()
+    {
+        if(_onSuccessAction != null)
+        {
+            _onSuccessAction.run();
+        }
+        else
+        {
+            LOGGER.debug("No onSuccess action, doing nothing.");
+        }
+
+        _isComplete = true;
+    }
+
+    public Runnable getOnSuccessAction()
+    {
+        return _onSuccessAction;
+    }
+
+    public FrameMatchingHandler onSuccess(Runnable onSuccessAction)
+    {
+        _onSuccessAction = onSuccessAction;
+        return this;
+    }
+
+    public FrameMatchingHandler onChannel(int channel)
+    {
+        _expectedChannel = channel;
+        return this;
+    }
+
+    public int getActualChannel()
+    {
+        return _actualChannel;
+    }
+
+    @Override
+    public boolean isComplete()
+    {
+        return _isComplete;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "FrameMatchingHandler [_symbolicDescriptor=" + _symbolicDescriptor
+                + ", _expectedChannel=" + expectedChannelString()
+                + "]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameSender.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameSender.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameSender.java
new file mode 100644
index 0000000..7099bee
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameSender.java
@@ -0,0 +1,63 @@
+/*
+ * 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.jms.test.testpeer;
+
+import org.apache.qpid.proton.amqp.Binary;
+
+class FrameSender implements AmqpPeerRunnable
+{
+    private final TestAmqpPeer _testAmqpPeer;
+    private final FrameType _type;
+    private final ListDescribedType _listDescribedType;
+    private final Binary _payload;
+    private ValueProvider _valueProvider;
+    private int _channel;
+
+    FrameSender(TestAmqpPeer testAmqpPeer, FrameType type, int channel, ListDescribedType listDescribedType, Binary payload)
+    {
+        _testAmqpPeer = testAmqpPeer;
+        _type = type;
+        _channel = channel;
+        _listDescribedType = listDescribedType;
+        _payload = payload;
+    }
+
+    @Override
+    public void run()
+    {
+        if(_valueProvider != null)
+        {
+            _valueProvider.setValues();
+        }
+
+        _testAmqpPeer.sendFrame(_type, _channel, _listDescribedType, _payload);
+    }
+
+    public FrameSender setValueProvider(ValueProvider valueProvider)
+    {
+        _valueProvider = valueProvider;
+        return this;
+    }
+
+    public FrameSender setChannel(int channel)
+    {
+        _channel = channel;
+        return this;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameType.java
new file mode 100644
index 0000000..cdc5a58
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameType.java
@@ -0,0 +1,22 @@
+/*
+ * 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.jms.test.testpeer;
+
+/** The frame type used in frame headers. The ordinal numbers are used to get the numeric value */
+public enum FrameType { AMQP, SASL }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithNoPayloadMatchingHandler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithNoPayloadMatchingHandler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithNoPayloadMatchingHandler.java
new file mode 100644
index 0000000..c6db0c9
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithNoPayloadMatchingHandler.java
@@ -0,0 +1,49 @@
+/*
+ * 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.jms.test.testpeer;
+
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public class FrameWithNoPayloadMatchingHandler extends AbstractFrameFieldAndPayloadMatchingHandler
+{
+
+    protected FrameWithNoPayloadMatchingHandler(FrameType frameType,
+                                                int channel,
+                                                UnsignedLong numericDescriptor,
+                                                Symbol symbolicDescriptor,
+                                                Map<Enum<?>, Matcher<?>> matchers,
+                                                Runnable onSuccess)
+    {
+        super(frameType, channel, numericDescriptor, symbolicDescriptor, matchers, onSuccess);
+    }
+
+    @Override
+    protected void verifyPayload(Binary payload)
+    {
+        if(payload != null && payload.getLength() > 0)
+        {
+            throw new IllegalArgumentException("Expected no payload but received payload of length: " + payload.getLength());
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithPayloadMatchingHandler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithPayloadMatchingHandler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithPayloadMatchingHandler.java
new file mode 100644
index 0000000..598f088
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/FrameWithPayloadMatchingHandler.java
@@ -0,0 +1,64 @@
+/*
+ * 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.jms.test.testpeer;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public class FrameWithPayloadMatchingHandler extends AbstractFrameFieldAndPayloadMatchingHandler
+{
+    private Matcher<Binary> _payloadMatcher;
+    private Binary _receivedPayload;
+
+    protected FrameWithPayloadMatchingHandler(FrameType frameType,
+                                                int channel,
+                                                UnsignedLong numericDescriptor,
+                                                Symbol symbolicDescriptor,
+                                                Map<Enum<?>, Matcher<?>> matchers,
+                                                Runnable onSuccess)
+    {
+        super(frameType, channel, numericDescriptor, symbolicDescriptor, matchers, onSuccess);
+    }
+
+    public void setPayloadMatcher(Matcher<Binary> payloadMatcher)
+    {
+        _payloadMatcher = payloadMatcher;
+    }
+
+    @Override
+    protected void verifyPayload(Binary payload)
+    {
+        if(_payloadMatcher != null)
+        {
+            assertThat("Payload should match", payload, _payloadMatcher);
+        }
+        _receivedPayload = payload;
+    }
+
+    public Binary getReceivedPayload()
+    {
+        return _receivedPayload;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/Handler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/Handler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/Handler.java
new file mode 100644
index 0000000..6fc7511
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/Handler.java
@@ -0,0 +1,28 @@
+/*
+ * 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.jms.test.testpeer;
+
+/**
+ * Handles incoming AMQP data, usually asserting that it matches expectations
+ * and potentially generating a response.
+ */
+interface Handler
+{
+    boolean isComplete();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandler.java
new file mode 100644
index 0000000..8834f52
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandler.java
@@ -0,0 +1,24 @@
+/*
+ * 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.jms.test.testpeer;
+
+interface HeaderHandler extends Handler
+{
+    void header(byte[] header, TestAmqpPeer peer);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandlerImpl.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandlerImpl.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandlerImpl.java
new file mode 100644
index 0000000..473fc7d
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/HeaderHandlerImpl.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jms.test.testpeer;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class HeaderHandlerImpl implements HeaderHandler
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(HeaderHandlerImpl.class.getName());
+
+    private final byte[] _expectedHeader;
+    private final byte[] _response;
+    private final Runnable _onSuccess;
+    private boolean _isComplete;
+
+    HeaderHandlerImpl(byte[] expectedHeader, byte[] response)
+    {
+       this(expectedHeader, response, null);
+    }
+
+    public HeaderHandlerImpl(byte[] header, byte[] response, Runnable onSuccess)
+    {
+        _expectedHeader = header;
+        _response = response;
+        _onSuccess = onSuccess;
+    }
+
+    @Override
+    public boolean isComplete()
+    {
+        return _isComplete;
+    }
+
+    @Override
+    public void header(byte[] header, TestAmqpPeer peer)
+    {
+        LOGGER.debug("About to check received header {}", new Binary(header));
+
+        assertThat("Header should match", header, equalTo(_expectedHeader));
+        peer.sendHeader(_response);
+        if(_onSuccess !=null)
+        {
+            _onSuccess.run();
+        }
+        _isComplete = true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "HeaderHandlerImpl [_expectedHeader=" + new Binary(_expectedHeader) + "]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ListDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ListDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ListDescribedType.java
new file mode 100644
index 0000000..06e1d91
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ListDescribedType.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.jms.test.testpeer;
+
+import java.util.Arrays;
+
+import org.apache.qpid.proton.amqp.DescribedType;
+
+public abstract class ListDescribedType implements DescribedType
+{
+    private final Object[] _fields;
+
+    public ListDescribedType(int numberOfFields)
+    {
+        _fields = new Object[numberOfFields];
+    }
+
+    @Override
+    public Object getDescribed()
+    {
+        //Return a List containing only the 'used fields' (i.e up to the highest field used)
+        int numUsedFields = 0;
+        for(int i = 0; i < _fields.length; i++)
+        {
+            if(_fields[i] != null)
+            {
+                numUsedFields = i + 1;
+            }
+        }
+
+        Object[] usedFields = new Object[numUsedFields];
+        for(int j = 0; j < numUsedFields; j++)
+        {
+            usedFields[j] = _fields[j];
+        }
+
+        return Arrays.asList(usedFields);
+    }
+
+    protected Object[] getFields()
+    {
+        return _fields;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ListDescribedType [descriptor=" + getDescriptor() + " fields=" + Arrays.toString(_fields) + "]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/MapDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/MapDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/MapDescribedType.java
new file mode 100644
index 0000000..59248d5
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/MapDescribedType.java
@@ -0,0 +1,46 @@
+/*
+ * 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.jms.test.testpeer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.DescribedType;
+
+public abstract class MapDescribedType implements DescribedType
+{
+    private final Map<Object,Object> _fields;
+
+    public MapDescribedType()
+    {
+        _fields = new HashMap<Object,Object>();
+    }
+
+    @Override
+    public Map<Object, Object> getDescribed()
+    {
+        return _fields;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "MapDescribedType [descriptor=" + getDescriptor() + " fields=" + _fields + "]";
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
new file mode 100644
index 0000000..a5e6561
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeer.java
@@ -0,0 +1,621 @@
+/*
+ * 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.jms.test.testpeer;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.qpid.jms.test.testpeer.describedtypes.Accepted;
+import org.apache.qpid.jms.test.testpeer.describedtypes.AttachFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.BeginFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.CloseFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.DetachFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.DispositionFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.EndFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.FlowFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.OpenFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.SaslMechanismsFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.SaslOutcomeFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.TransferFrame;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.ApplicationPropertiesDescribedType;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.HeaderDescribedType;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.MessageAnnotationsDescribedType;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.PropertiesDescribedType;
+import org.apache.qpid.jms.test.testpeer.matchers.AttachMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.BeginMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.CloseMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.DetachMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.DispositionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.EndMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.FlowMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.OpenMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.SaslInitMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.TransferMatcher;
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.UnsignedShort;
+import org.apache.qpid.proton.codec.Data;
+import org.apache.qpid.proton.engine.impl.AmqpHeader;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+// TODO should expectXXXYYYZZZ methods just be expect(matcher)?
+public class TestAmqpPeer implements AutoCloseable
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(TestAmqpPeer.class.getName());
+
+    /** Roles are represented as booleans - see AMQP spec 2.8.1*/
+    private static final boolean SENDER_ROLE = false;
+
+    /** Roles are represented as booleans - see AMQP spec 2.8.1*/
+    private static final boolean RECEIVER_ROLE = true;
+
+    private static final UnsignedByte ATTACH_SND_SETTLE_MODE_UNSETTLED = UnsignedByte.valueOf((byte) 0);
+
+    private static final UnsignedByte ATTACH_RCV_SETTLE_MODE_FIRST = UnsignedByte.valueOf((byte)0);
+
+    private final TestAmqpPeerRunner _driverRunnable;
+    private final Thread _driverThread;
+
+    /**
+     * Guarded by {@link #_handlersLock}
+     */
+    private final List<Handler> _handlers = new ArrayList<Handler>();
+    private final Object _handlersLock = new Object();
+
+    /**
+     * Guarded by {@link #_handlersLock}
+     */
+    private CountDownLatch _handlersCompletedLatch;
+
+    private volatile int _nextLinkHandle = 100;
+
+    public TestAmqpPeer(int port) throws IOException
+    {
+        _driverRunnable = new TestAmqpPeerRunner(port, this);
+        _driverThread = new Thread(_driverRunnable, "MockAmqpPeerThread");
+        _driverThread.start();
+    }
+
+    /**
+     * Shuts down the test peer, throwing any Throwable
+     * that occurred on the peer, or validating that no
+     * unused matchers remain.
+     */
+    @Override
+    public void close() throws Exception
+    {
+        _driverRunnable.stop();
+
+        try
+        {
+            _driverThread.join(30000);
+        }
+        catch (InterruptedException e)
+        {
+            Thread.currentThread().interrupt();
+        }
+        finally
+        {
+            Throwable throwable = getThrowable();
+            if(throwable == null)
+            {
+                synchronized(_handlersLock)
+                {
+                    assertThat(_handlers, Matchers.empty());
+                }
+            }
+            else
+            {
+                //AutoClosable can't handle throwing Throwables, so we wrap it.
+                throw new RuntimeException("TestPeer caught throwable during run", throwable);
+            }
+        }
+    }
+
+    public Throwable getThrowable()
+    {
+        return _driverRunnable.getException();
+    }
+
+    public void receiveHeader(byte[] header)
+    {
+        Handler handler = getFirstHandler();
+        if(handler instanceof HeaderHandler)
+        {
+            ((HeaderHandler)handler).header(header,this);
+            if(handler.isComplete())
+            {
+                removeFirstHandler();
+            }
+        }
+        else
+        {
+            throw new IllegalStateException("Received header but the next handler is a " + handler);
+        }
+    }
+
+    public void receiveFrame(int type, int channel, DescribedType describedType, Binary payload)
+    {
+        Handler handler = getFirstHandler();
+        if(handler instanceof FrameHandler)
+        {
+            ((FrameHandler)handler).frame(type, channel, describedType, payload, this);
+            if(handler.isComplete())
+            {
+                removeFirstHandler();
+            }
+        }
+        else
+        {
+            throw new IllegalStateException("Received frame but the next handler is a " + handler);
+        }
+    }
+
+    private void removeFirstHandler()
+    {
+        synchronized(_handlersLock)
+        {
+            Handler h = _handlers.remove(0);
+            if(_handlersCompletedLatch != null)
+            {
+                _handlersCompletedLatch.countDown();
+            }
+            LOGGER.trace("Removed completed handler: {}", h);
+        }
+    }
+
+    private void addHandler(Handler handler)
+    {
+        synchronized(_handlersLock)
+        {
+            _handlers.add(handler);
+            LOGGER.trace("Added handler: {}", handler);
+        }
+    }
+
+    private Handler getFirstHandler()
+    {
+        synchronized(_handlersLock)
+        {
+            if(_handlers.isEmpty())
+            {
+                throw new IllegalStateException("No handlers");
+            }
+            return _handlers.get(0);
+        }
+    }
+
+    public void waitForAllHandlersToComplete(int timeoutMillis) throws InterruptedException
+    {
+        synchronized(_handlersLock)
+        {
+            _handlersCompletedLatch = new CountDownLatch(_handlers.size());
+        }
+
+        boolean countedDownOk = _handlersCompletedLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+
+        Assert.assertTrue(
+                "All handlers should have completed within the " + timeoutMillis + "ms timeout", countedDownOk);
+    }
+
+    void sendHeader(byte[] header)
+    {
+        LOGGER.debug("About to send header: {}", new Binary(header));
+        _driverRunnable.sendBytes(header);
+    }
+
+    public void sendFrame(FrameType type, int channel, DescribedType describedType, Binary payload)
+    {
+        if(channel < 0)
+        {
+            throw new IllegalArgumentException("Frame must be sent on a channel >= 0");
+        }
+
+        LOGGER.debug("About to send: {}", describedType);
+        byte[] output = AmqpDataFramer.encodeFrame(type, channel, describedType, payload);
+        _driverRunnable.sendBytes(output);
+    }
+
+    public void expectAnonymousConnect(boolean authorize)
+    {
+        SaslMechanismsFrame saslMechanismsFrame = new SaslMechanismsFrame().setSaslServerMechanisms(Symbol.valueOf("ANONYMOUS"));
+        addHandler(new HeaderHandlerImpl(AmqpHeader.SASL_HEADER, AmqpHeader.SASL_HEADER,
+                                            new FrameSender(
+                                                    this, FrameType.SASL, 0,
+                                                    saslMechanismsFrame, null)));
+
+        addHandler(new SaslInitMatcher()
+            .withMechanism(equalTo(Symbol.valueOf("ANONYMOUS")))
+            .onSuccess(new AmqpPeerRunnable()
+            {
+                @Override
+                public void run()
+                {
+                    TestAmqpPeer.this.sendFrame(
+                            FrameType.SASL, 0,
+                            new SaslOutcomeFrame().setCode(UnsignedByte.valueOf((byte)0)),
+                            null);
+                    _driverRunnable.expectHeader();
+                }
+            }));
+
+        addHandler(new HeaderHandlerImpl(AmqpHeader.HEADER, AmqpHeader.HEADER));
+
+        addHandler(new OpenMatcher()
+            .withContainerId(notNullValue(String.class))
+            .onSuccess(new FrameSender(
+                    this, FrameType.AMQP, 0,
+                    new OpenFrame().setContainerId("test-amqp-peer-container-id"),
+                    null)));
+    }
+
+    public void expectPlainConnect(String username, String password, boolean authorize)
+    {
+        SaslMechanismsFrame saslMechanismsFrame = new SaslMechanismsFrame().setSaslServerMechanisms(Symbol.valueOf("PLAIN"));
+        addHandler(new HeaderHandlerImpl(AmqpHeader.SASL_HEADER, AmqpHeader.SASL_HEADER,
+                                            new FrameSender(
+                                                    this, FrameType.SASL, 0,
+                                                    saslMechanismsFrame, null)));
+
+        byte[] usernameBytes = username.getBytes();
+        byte[] passwordBytes = password.getBytes();
+        byte[] data = new byte[usernameBytes.length+passwordBytes.length+2];
+        System.arraycopy(usernameBytes, 0, data, 1, usernameBytes.length);
+        System.arraycopy(passwordBytes, 0, data, 2 + usernameBytes.length, passwordBytes.length);
+
+        addHandler(new SaslInitMatcher()
+            .withMechanism(equalTo(Symbol.valueOf("PLAIN")))
+            .withInitialResponse(equalTo(new Binary(data)))
+            .onSuccess(new AmqpPeerRunnable()
+            {
+                @Override
+                public void run()
+                {
+                    TestAmqpPeer.this.sendFrame(
+                            FrameType.SASL, 0,
+                            new SaslOutcomeFrame().setCode(UnsignedByte.valueOf((byte)0)),
+                            null);
+                    _driverRunnable.expectHeader();
+                }
+            }));
+
+        addHandler(new HeaderHandlerImpl(AmqpHeader.HEADER, AmqpHeader.HEADER));
+
+        addHandler(new OpenMatcher()
+            .withContainerId(notNullValue(String.class))
+            .onSuccess(new FrameSender(
+                    this, FrameType.AMQP, 0,
+                    new OpenFrame().setContainerId("test-amqp-peer-container-id"),
+                    null)));
+    }
+
+    public void expectClose()
+    {
+        addHandler(new CloseMatcher()
+            .withError(Matchers.nullValue())
+            .onSuccess(new FrameSender(this, FrameType.AMQP, 0,
+                    new CloseFrame(),
+                    null)));
+    }
+
+    public void expectBegin(boolean expectSessionFlow)
+    {
+        final BeginMatcher beginMatcher = new BeginMatcher()
+                .withRemoteChannel(nullValue())
+                .withNextOutgoingId(notNullValue())
+                .withIncomingWindow(notNullValue())
+                .withOutgoingWindow(notNullValue());
+
+        // The response will have its remoteChannel field dynamically set based on incoming value
+        final BeginFrame beginResponse = new BeginFrame()
+            .setNextOutgoingId(UnsignedInteger.ZERO)
+            .setIncomingWindow(UnsignedInteger.ZERO)
+            .setOutgoingWindow(UnsignedInteger.ZERO);
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender beginResponseSender = new FrameSender(this, FrameType.AMQP, -1, beginResponse, null);
+        beginResponseSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                beginResponseSender.setChannel(beginMatcher.getActualChannel());
+                beginResponse.setRemoteChannel(
+                        UnsignedShort.valueOf((short) beginMatcher.getActualChannel()));
+            }
+        });
+        beginMatcher.onSuccess(beginResponseSender);
+
+        addHandler(beginMatcher);
+
+        if(expectSessionFlow)
+        {
+            expectSessionFlow();
+        }
+    }
+
+    public void expectEnd()
+    {
+        final EndMatcher endMatcher = new EndMatcher();
+
+        final EndFrame endResponse = new EndFrame();
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender frameSender = new FrameSender(this, FrameType.AMQP, -1, endResponse, null);
+        frameSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                frameSender.setChannel(endMatcher.getActualChannel());
+            }
+        });
+        endMatcher.onSuccess(frameSender);
+
+        addHandler(endMatcher);
+    }
+
+    public void expectSenderAttach()
+    {
+        final AttachMatcher attachMatcher = new AttachMatcher()
+                .withName(notNullValue())
+                .withHandle(notNullValue())
+                .withRole(equalTo(SENDER_ROLE))
+                .withSndSettleMode(equalTo(ATTACH_SND_SETTLE_MODE_UNSETTLED))
+                .withRcvSettleMode(equalTo(ATTACH_RCV_SETTLE_MODE_FIRST))
+                .withSource(notNullValue())
+                .withTarget(notNullValue());
+
+        UnsignedInteger linkHandle = UnsignedInteger.valueOf(_nextLinkHandle++);
+        final AttachFrame attachResponse = new AttachFrame()
+                            .setHandle(linkHandle)
+                            .setRole(RECEIVER_ROLE)
+                            .setSndSettleMode(ATTACH_SND_SETTLE_MODE_UNSETTLED)
+                            .setRcvSettleMode(ATTACH_RCV_SETTLE_MODE_FIRST);
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender attachResponseSender = new FrameSender(this, FrameType.AMQP, -1, attachResponse, null);
+        attachResponseSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                attachResponseSender.setChannel(attachMatcher.getActualChannel());
+                attachResponse.setName(attachMatcher.getReceivedName());
+                attachResponse.setSource(attachMatcher.getReceivedSource());
+                attachResponse.setTarget(attachMatcher.getReceivedTarget());
+            }
+        });
+
+        final FlowFrame flowFrame = new FlowFrame().setNextIncomingId(UnsignedInteger.ZERO)
+                .setIncomingWindow(UnsignedInteger.valueOf(2048))
+                .setNextOutgoingId(UnsignedInteger.ZERO)
+                .setOutgoingWindow(UnsignedInteger.valueOf(2048))
+                .setLinkCredit(UnsignedInteger.valueOf(100))
+                .setHandle(linkHandle);
+
+        // The flow frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender flowFrameSender = new FrameSender(this, FrameType.AMQP, -1, flowFrame, null);
+        flowFrameSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                flowFrameSender.setChannel(attachMatcher.getActualChannel());
+                flowFrame.setDeliveryCount(attachMatcher.getReceivedInitialDeliveryCount());
+            }
+        });
+
+        CompositeAmqpPeerRunnable composite = new CompositeAmqpPeerRunnable();
+        composite.add(attachResponseSender);
+        composite.add(flowFrameSender);
+
+        attachMatcher.onSuccess(composite);
+
+        addHandler(attachMatcher);
+    }
+
+    public void expectReceiverAttach()
+    {
+        final AttachMatcher attachMatcher = new AttachMatcher()
+                .withName(notNullValue())
+                .withHandle(notNullValue())
+                .withRole(equalTo(RECEIVER_ROLE))
+                .withSndSettleMode(equalTo(ATTACH_SND_SETTLE_MODE_UNSETTLED))
+                .withRcvSettleMode(equalTo(ATTACH_RCV_SETTLE_MODE_FIRST))
+                .withSource(notNullValue())
+                .withTarget(notNullValue());
+
+        UnsignedInteger linkHandle = UnsignedInteger.valueOf(_nextLinkHandle++);
+        final AttachFrame attachResponse = new AttachFrame()
+                            .setHandle(linkHandle)
+                            .setRole(SENDER_ROLE)
+                            .setSndSettleMode(ATTACH_SND_SETTLE_MODE_UNSETTLED)
+                            .setRcvSettleMode(ATTACH_RCV_SETTLE_MODE_FIRST)
+                            .setInitialDeliveryCount(UnsignedInteger.ZERO);
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender attachResponseSender = new FrameSender(this, FrameType.AMQP, -1, attachResponse, null);
+        attachResponseSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                attachResponseSender.setChannel(attachMatcher.getActualChannel());
+                attachResponse.setName(attachMatcher.getReceivedName());
+                attachResponse.setSource(attachMatcher.getReceivedSource());
+                attachResponse.setTarget(attachMatcher.getReceivedTarget());
+            }
+        });
+
+        attachMatcher.onSuccess(attachResponseSender);
+
+        addHandler(attachMatcher);
+    }
+
+    public void expectDetach(boolean close)
+    {
+        final DetachMatcher detachMatcher = new DetachMatcher().withClosed(equalTo(close));
+
+        final DetachFrame detachResponse = new DetachFrame()
+                                .setHandle(UnsignedInteger.valueOf(_nextLinkHandle - 1)); // TODO: this needs to be the value used in the attach response
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender detachResponseSender = new FrameSender(this, FrameType.AMQP, -1, detachResponse, null);
+        detachResponseSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                detachResponseSender.setChannel(detachMatcher.getActualChannel());
+            }
+        });
+
+        detachMatcher.onSuccess(detachResponseSender);
+
+        addHandler(detachMatcher);
+    }
+
+    public void expectSessionFlow()
+    {
+        final FlowMatcher flowMatcher = new FlowMatcher()
+                        .withLinkCredit(Matchers.nullValue())
+                        .withHandle(Matchers.nullValue());
+
+        addHandler(flowMatcher);
+    }
+
+    public void expectLinkFlow()
+    {
+        final FlowMatcher flowMatcher = new FlowMatcher()
+                        .withLinkCredit(Matchers.greaterThan(UnsignedInteger.ZERO));
+
+        addHandler(flowMatcher);
+    }
+
+    public void expectLinkFlowRespondWithTransfer(final HeaderDescribedType headerDescribedType,
+                                                  final MessageAnnotationsDescribedType messageAnnotationsDescribedType,
+                                                  final PropertiesDescribedType propertiesDescribedType,
+                                                  final ApplicationPropertiesDescribedType appPropertiesDescribedType,
+                                                  final DescribedType content)
+    {
+        final FlowMatcher flowMatcher = new FlowMatcher()
+                        .withLinkCredit(Matchers.greaterThan(UnsignedInteger.ZERO));
+
+        final TransferFrame transferResponse = new TransferFrame()
+            .setHandle(UnsignedInteger.valueOf(_nextLinkHandle - 1)) // TODO: this needs to be the value used in the attach response
+            .setDeliveryId(UnsignedInteger.ZERO) // TODO: we shouldn't assume this is the first transfer on the session
+            .setDeliveryTag(new Binary("theDeliveryTag".getBytes()))
+            .setMessageFormat(UnsignedInteger.ZERO)
+            .setSettled(false);
+
+        Data payloadData = Proton.data(1024);
+
+        if(headerDescribedType != null)
+        {
+            payloadData.putDescribedType(headerDescribedType);
+        }
+
+        if(messageAnnotationsDescribedType != null)
+        {
+            payloadData.putDescribedType(messageAnnotationsDescribedType);
+        }
+
+        if(propertiesDescribedType != null)
+        {
+            payloadData.putDescribedType(propertiesDescribedType);
+        }
+
+        if(appPropertiesDescribedType != null)
+        {
+            payloadData.putDescribedType(appPropertiesDescribedType);
+        }
+
+        if(content != null)
+        {
+            payloadData.putDescribedType(content);
+        }
+
+        Binary payload = payloadData.encode();
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender transferResponseSender = new FrameSender(this, FrameType.AMQP, -1, transferResponse, payload);
+        transferResponseSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                transferResponseSender.setChannel(flowMatcher.getActualChannel());
+            }
+        });
+
+        flowMatcher.onSuccess(transferResponseSender);
+
+        addHandler(flowMatcher);
+    }
+
+    public void expectTransfer(Matcher<Binary> expectedPayloadMatcher)
+    {
+        final TransferMatcher transferMatcher = new TransferMatcher();
+        transferMatcher.setPayloadMatcher(expectedPayloadMatcher);
+
+        final DispositionFrame dispositionFrame = new DispositionFrame()
+                                                   .setRole(RECEIVER_ROLE)
+                                                   .setSettled(true)
+                                                   .setState(new Accepted());
+
+        // The response frame channel will be dynamically set based on the incoming frame. Using the -1 is an illegal placeholder.
+        final FrameSender dispositionFrameSender = new FrameSender(this, FrameType.AMQP, -1, dispositionFrame, null);
+        dispositionFrameSender.setValueProvider(new ValueProvider()
+        {
+            @Override
+            public void setValues()
+            {
+                dispositionFrameSender.setChannel(transferMatcher.getActualChannel());
+                dispositionFrame.setFirst(transferMatcher.getReceivedDeliveryId());
+            }
+        });
+        transferMatcher.onSuccess(dispositionFrameSender);
+
+        addHandler(transferMatcher);
+    }
+
+    public void expectDispositionThatIsAcceptedAndSettled()
+    {
+        addHandler(new DispositionMatcher()
+            .withSettled(equalTo(true))
+            .withState(new DescriptorMatcher(Accepted.DESCRIPTOR_CODE, Accepted.DESCRIPTOR_SYMBOL)));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
new file mode 100644
index 0000000..5039691
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestAmqpPeerRunner.java
@@ -0,0 +1,153 @@
+/*
+ * 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.jms.test.testpeer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class TestAmqpPeerRunner implements Runnable
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(TestAmqpPeerRunner.class);
+
+    private final ServerSocket _serverSocket;
+
+    /** TODO handle multiple connections */
+    private Socket _clientSocket;
+    private OutputStream _networkOutputStream;
+
+    private final Object _inputHandlingLock = new Object();
+    private final TestFrameParser _testFrameParser;
+
+    private volatile Throwable _throwable;
+
+    public TestAmqpPeerRunner(int port, TestAmqpPeer peer) throws IOException
+    {
+        _serverSocket = new ServerSocket(port);
+        _testFrameParser = new TestFrameParser(peer);
+    }
+
+    @Override
+    public void run()
+    {
+        try
+        (
+            Socket clientSocket = _serverSocket.accept();
+            InputStream networkInputStream = clientSocket.getInputStream();
+            OutputStream networkOutputStream = clientSocket.getOutputStream();
+        )
+        {
+            _clientSocket = clientSocket;
+            _networkOutputStream = networkOutputStream;
+
+            int bytesRead;
+            byte[] networkInputBytes = new byte[1024];
+
+            LOGGER.trace("Attempting read");
+            while((bytesRead = networkInputStream.read(networkInputBytes)) != -1)
+            {
+                //prevent stop() from killing the socket while the frame parser might be using it handling input
+                synchronized(_inputHandlingLock)
+                {
+                    ByteBuffer networkInputByteBuffer = ByteBuffer.wrap(networkInputBytes, 0, bytesRead);
+
+                    LOGGER.debug("Read: {}", new Binary(networkInputBytes, 0, bytesRead));
+
+                    _testFrameParser.input(networkInputByteBuffer);
+                }
+                LOGGER.trace("Attempting read");
+            }
+
+            LOGGER.trace("Exited read loop");
+        }
+        catch (Throwable t)
+        {
+            if(!_serverSocket.isClosed())
+            {
+                LOGGER.error("Problem in peer", t);
+                _throwable = t;
+            }
+            else
+            {
+                LOGGER.debug("Caught throwable, ignoring as socket is closed: " + t);
+            }
+        }
+        finally
+        {
+            try
+            {
+                _serverSocket.close();
+            }
+            catch (IOException e)
+            {
+                LOGGER.error("Unable to close server socket", e);
+            }
+        }
+    }
+
+    public void stop() throws IOException
+    {
+        //wait for the frame parser to handle any input it already had
+        synchronized(_inputHandlingLock)
+        {
+            try
+            {
+                _serverSocket.close();
+            }
+            finally
+            {
+                if(_clientSocket != null)
+                {
+                    _clientSocket.close();
+                }
+            }
+        }
+    }
+
+    public void expectHeader()
+    {
+        _testFrameParser.expectHeader();
+    }
+
+    public void sendBytes(byte[] bytes)
+    {
+        LOGGER.debug("Sending: {}", new Binary(bytes));
+        try
+        {
+            _networkOutputStream.write(bytes);
+            _networkOutputStream.flush();
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Throwable getException()
+    {
+        return _throwable;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestFrameParser.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestFrameParser.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestFrameParser.java
new file mode 100644
index 0000000..0f852c2
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/TestFrameParser.java
@@ -0,0 +1,375 @@
+/*
+ * 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.jms.test.testpeer;
+
+import static org.apache.qpid.proton.engine.TransportResultFactory.error;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.codec.Data;
+import org.apache.qpid.proton.codec.DecodeException;
+import org.apache.qpid.proton.engine.TransportResult;
+import org.apache.qpid.proton.engine.TransportResultFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class TestFrameParser
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(TestFrameParser.class);
+
+    private enum State
+    {
+        HEADER0,
+        HEADER1,
+        HEADER2,
+        HEADER3,
+        HEADER4,
+        HEADER5,
+        HEADER6,
+        HEADER7,
+        SIZE_0,
+        SIZE_1,
+        SIZE_2,
+        SIZE_3,
+        PRE_PARSE,
+        BUFFERING,
+        PARSING,
+        ERROR
+    }
+
+
+    private State _state = State.HEADER0;
+
+    /** the stated size of the current frame */
+    private int _size;
+
+    /** holds the current frame that is being parsed */
+    private ByteBuffer _frameBuffer;
+
+    private TestAmqpPeer _peer;
+
+    /** PHTOD remove args? */
+    public TestFrameParser(TestAmqpPeer peer)
+    {
+        _peer = peer;
+    }
+
+    public void expectHeader()
+    {
+        _state = State.HEADER0;
+    }
+
+    public void input(final ByteBuffer input)
+    {
+        TransportResult frameParsingError = null;
+        int size = _size;
+        ByteBuffer nextFramesInput = null;
+        byte[] header = new byte[8];
+
+        boolean transportAccepting = true;
+
+        ByteBuffer currentInput = input;
+        while(currentInput.hasRemaining() && _state != State.ERROR && transportAccepting)
+        {
+            switch(_state)
+            {
+                case HEADER0:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[0] = c;
+                        _state = State.HEADER1;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER1:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[1] = c;
+                        _state = State.HEADER2;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER2:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[2] = c;
+                        _state = State.HEADER3;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER3:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[3] = c;
+                        _state = State.HEADER4;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER4:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[4] = c;
+                        _state = State.HEADER5;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER5:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[5] = c;
+                        _state = State.HEADER6;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER6:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[6] = c;
+                        _state = State.HEADER7;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case HEADER7:
+                    if(currentInput.hasRemaining())
+                    {
+                        byte c = currentInput.get();
+                        header[7] = c;
+                        _peer.receiveHeader(header);
+                        _state = State.SIZE_0;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                case SIZE_0:
+                    if(!currentInput.hasRemaining())
+                    {
+                        break;
+                    }
+                    if(currentInput.remaining() >= 4)
+                    {
+                        size = currentInput.getInt();
+                        _state = State.PRE_PARSE;
+                        break;
+                    }
+                    else
+                    {
+                        size = (currentInput.get() << 24) & 0xFF000000;
+                        if(!currentInput.hasRemaining())
+                        {
+                            _state = State.SIZE_1;
+                            break;
+                        }
+                    }
+                case SIZE_1:
+                    size |= (currentInput.get() << 16) & 0xFF0000;
+                    if(!currentInput.hasRemaining())
+                    {
+                        _state = State.SIZE_2;
+                        break;
+                    }
+                case SIZE_2:
+                    size |= (currentInput.get() << 8) & 0xFF00;
+                    if(!currentInput.hasRemaining())
+                    {
+                        _state = State.SIZE_3;
+                        break;
+                    }
+                case SIZE_3:
+                    size |= currentInput.get() & 0xFF;
+                    _state = State.PRE_PARSE;
+
+                case PRE_PARSE:
+                    ;
+                    if(size < 8)
+                    {
+                        frameParsingError = error("specified frame size %d smaller than minimum frame header "
+                                                         + "size %d",
+                                                         _size, 8);
+                        _state = State.ERROR;
+                        break;
+                    }
+
+                    if(currentInput.remaining() < size-4)
+                    {
+                        _frameBuffer = ByteBuffer.allocate(size-4);
+                        _frameBuffer.put(currentInput);
+                        _state = State.BUFFERING;
+                        break;
+                    }
+                case BUFFERING:
+                    if(_frameBuffer != null)
+                    {
+                        if(currentInput.remaining() < _frameBuffer.remaining())
+                        {
+                            // in does not contain enough bytes to complete the frame
+                            _frameBuffer.put(currentInput);
+                            break;
+                        }
+                        else
+                        {
+                            ByteBuffer dup = currentInput.duplicate();
+                            dup.limit(dup.position()+_frameBuffer.remaining());
+                            currentInput.position(currentInput.position()+_frameBuffer.remaining());
+                            _frameBuffer.put(dup);
+                            nextFramesInput = currentInput;
+                            _frameBuffer.flip();
+                            currentInput = _frameBuffer;
+                            _state = State.PARSING;
+                        }
+                    }
+
+                case PARSING:
+
+                    int dataOffset = (currentInput.get() << 2) & 0x3FF;
+
+                    if(dataOffset < 8)
+                    {
+                        frameParsingError = error("specified frame data offset %d smaller than minimum frame header size %d", dataOffset, 8);
+                        _state = State.ERROR;
+                        break;
+                    }
+                    else if(dataOffset > size)
+                    {
+                        frameParsingError = error("specified frame data offset %d larger than the frame size %d", dataOffset, _size);
+                        _state = State.ERROR;
+                        break;
+                    }
+
+                    // type
+
+                    int type = currentInput.get() & 0xFF;
+                    int channel = currentInput.getShort() & 0xFF;
+
+                    // note that this skips over the extended header if it's present
+                    if(dataOffset!=8)
+                    {
+                        currentInput.position(currentInput.position()+dataOffset-8);
+                    }
+
+                    // oldIn null iff not working on duplicated buffer
+                    final int frameBodySize = size - dataOffset;
+                    if(nextFramesInput == null)
+                    {
+                        nextFramesInput = currentInput;
+                        currentInput = currentInput.duplicate();
+                        final int endPos = currentInput.position() + frameBodySize;
+                        currentInput.limit(endPos);
+                        nextFramesInput.position(endPos);
+
+                    }
+
+                    // in's remaining bytes are now exactly those of one complete frame body
+                    // oldIn's remaining bytes are those beyond the end of currentIn's frame
+
+                    try
+                    {
+                        if (frameBodySize > 0)
+                        {
+
+                            Data data = Data.Factory.create();
+                            data.decode(currentInput);
+                            Data.DataType dataType = data.type();
+                            if(dataType != Data.DataType.DESCRIBED)
+                            {
+                                throw new IllegalArgumentException("Frame body type expected to be " + Data.DataType.DESCRIBED + " but was: " + dataType);
+                            }
+
+                            DescribedType describedType = data.getDescribedType();
+                            LOGGER.debug("Received described type: {}", describedType);
+
+                            Binary payload;
+
+                            if(currentInput.hasRemaining())
+                            {
+                                byte[] payloadBytes = new byte[currentInput.remaining()];
+                                currentInput.get(payloadBytes);
+                                payload = new Binary(payloadBytes);
+                            }
+                            else
+                            {
+                                payload = null;
+                            }
+
+                            _peer.receiveFrame(type, channel, describedType, payload);
+                        }
+                        else
+                        {
+                            LOGGER.debug("Ignored empty frame");
+                        }
+                        _size = 0;
+                        currentInput = nextFramesInput;
+                        nextFramesInput = null;
+                        _frameBuffer = null;
+                        if(_state != State.HEADER0)
+                        {
+                            _state = State.SIZE_0;
+                        }
+                    }
+                    catch (DecodeException ex)
+                    {
+                        _state = State.ERROR;
+                        frameParsingError = error(ex);
+                    }
+                    break;
+                case ERROR:
+                    // do nothing
+            }
+
+        }
+
+        _size = size;
+
+        if(_state == State.ERROR)
+        {
+            // TODO throw non-proton exception
+            if(frameParsingError != null)
+            {
+                frameParsingError.checkIsOk();
+            }
+            else
+            {
+                TransportResultFactory.error("Unable to parse, probably because of a previous error").checkIsOk();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ValueProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ValueProvider.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ValueProvider.java
new file mode 100644
index 0000000..0f8d1ca
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/ValueProvider.java
@@ -0,0 +1,28 @@
+/*
+ * 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.jms.test.testpeer;
+
+/**
+ * Typically used by {@link FrameSender} to dynamically set values on the outgoing frame,
+ * based on the values of the incoming one.
+ */
+public interface ValueProvider
+{
+    void setValues();
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Accepted.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Accepted.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Accepted.java
new file mode 100644
index 0000000..171a1e0
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Accepted.java
@@ -0,0 +1,54 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class Accepted extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:accepted:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000024L);
+
+
+
+    public Accepted(Object... fields)
+    {
+        super(0);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/AttachFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/AttachFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/AttachFrame.java
new file mode 100644
index 0000000..ecef518
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/AttachFrame.java
@@ -0,0 +1,152 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class AttachFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:attach:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000012L);
+
+
+    private static final int FIELD_NAME = 0;
+    private static final int FIELD_HANDLE = 1;
+    private static final int FIELD_ROLE = 2;
+    private static final int FIELD_SND_SETTLE_MODE = 3;
+    private static final int FIELD_RCV_SETTLE_MODE = 4;
+    private static final int FIELD_SOURCE = 5;
+    private static final int FIELD_TARGET = 6;
+    private static final int FIELD_UNSETTLED = 7;
+    private static final int FIELD_INCOMPLETE_UNSETTLED = 8;
+    private static final int FIELD_INITIAL_DELIVERY_COUNT = 9;
+    private static final int FIELD_MAX_MESSAGE_SIZE = 10;
+    private static final int FIELD_OFFERED_CAPABILITIES = 11;
+    private static final int FIELD_DESIRED_CAPABILITIES = 12;
+    private static final int FIELD_PROPERTIES = 13;
+
+    public AttachFrame(Object... fields)
+    {
+        super(14);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public AttachFrame setName(Object o)
+    {
+        getFields()[FIELD_NAME] = o;
+        return this;
+    }
+
+    public AttachFrame setHandle(Object o)
+    {
+        getFields()[FIELD_HANDLE] = o;
+        return this;
+    }
+
+    public AttachFrame setRole(Object o)
+    {
+        getFields()[FIELD_ROLE] = o;
+        return this;
+    }
+
+    public AttachFrame setSndSettleMode(Object o)
+    {
+        getFields()[FIELD_SND_SETTLE_MODE] = o;
+        return this;
+    }
+
+    public AttachFrame setRcvSettleMode(Object o)
+    {
+        getFields()[FIELD_RCV_SETTLE_MODE] = o;
+        return this;
+    }
+
+    public AttachFrame setSource(Object o)
+    {
+        getFields()[FIELD_SOURCE] = o;
+        return this;
+    }
+
+    public AttachFrame setTarget(Object o)
+    {
+        getFields()[FIELD_TARGET] = o;
+        return this;
+    }
+
+    public AttachFrame setUnsettled(Object o)
+    {
+        getFields()[FIELD_UNSETTLED] = o;
+        return this;
+    }
+
+    public AttachFrame setIncompleteUnsettled(Object o)
+    {
+        getFields()[FIELD_INCOMPLETE_UNSETTLED] = o;
+        return this;
+    }
+
+    public AttachFrame setInitialDeliveryCount(Object o)
+    {
+        getFields()[FIELD_INITIAL_DELIVERY_COUNT] = o;
+        return this;
+    }
+
+    public AttachFrame setMaxMessageSize(Object o)
+    {
+        getFields()[FIELD_MAX_MESSAGE_SIZE] = o;
+        return this;
+    }
+
+    public AttachFrame setOfferedCapabilities(Object o)
+    {
+        getFields()[FIELD_OFFERED_CAPABILITIES] = o;
+        return this;
+    }
+
+    public AttachFrame setDesiredCapabilities(Object o)
+    {
+        getFields()[FIELD_DESIRED_CAPABILITIES] = o;
+        return this;
+    }
+
+    public AttachFrame setProperties(Object o)
+    {
+        getFields()[FIELD_PROPERTIES] = o;
+        return this;
+    }
+
+}
+


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


[16/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
new file mode 100644
index 0000000..234caaa
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpTypedObjectDelegate.java
@@ -0,0 +1,103 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.messaging.AmqpSequence;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Wrapper around an AMQP Message instance that will be treated as a JMS ObjectMessage
+ * type.
+ */
+public class AmqpTypedObjectDelegate implements AmqpObjectTypeDelegate {
+
+    private final Message message;
+
+    /**
+     * Create a new delegate that uses Java serialization to store the message content.
+     *
+     * @param message
+     *        the AMQP message instance where the object is to be stored / read.
+     */
+    public AmqpTypedObjectDelegate(Message message) {
+        this.message = message;
+    }
+
+    @Override
+    public Serializable getObject() throws IOException, ClassNotFoundException {
+        // TODO: this should actually return a snapshot of the object, so we
+        // need to save the bytes so we can return an equal/unmodified object later
+
+        Section body = message.getBody();
+        if (body == null) {
+            return null;
+        } else if (body instanceof AmqpValue) {
+            // TODO: This is assuming the object can be immediately returned, and is
+            //       Serializable. We will actually have to ensure elements are
+            //       Serializable and e.g convert the Uint/Ubyte etc wrappers.
+            return (Serializable) ((AmqpValue) body).getValue();
+        } else if (body instanceof Data) {
+            // TODO: return as byte[]? ByteBuffer?
+            throw new UnsupportedOperationException("Data support still to be added");
+        } else if (body instanceof AmqpSequence) {
+            // TODO: return as list?
+            throw new UnsupportedOperationException("AmqpSequence support still to be added");
+        } else {
+            throw new IllegalStateException("Unexpected body type: " + body.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public void setObject(Serializable value) throws IOException {
+        if (value == null) {
+            // TODO: verify whether not sending a body is OK, send some form of
+            // null (AmqpValue containing null) instead if it isn't?
+            message.setBody(null);
+        } else if (isSupportedAmqpValueObjectType(value)) {
+            // TODO: This is a temporary hack, we actually need to take a snapshot of the object
+            // at this point in time, not simply set the object itself into the Proton message.
+            // We will need to encode it now, first to save the snapshot to send, and also to
+            // verify up front that we can actually send it later.
+
+            // Even if we do that we would currently then need to decode it later to set the
+            // body to send, unless we augment Proton to allow setting the bytes directly.
+            // We will always need to decode bytes to return a snapshot from getObject(). We
+            // will need to save the bytes somehow to support that on received messages.
+            message.setBody(new AmqpValue(value));
+        } else {
+            // TODO: Data and AmqpSequence?
+            throw new IllegalArgumentException("Encoding this object type with the AMQP type system is not supported: " + value.getClass().getName());
+        }
+
+        // TODO: ensure content type is not set (assuming we aren't using data sections)?
+    }
+
+    private boolean isSupportedAmqpValueObjectType(Serializable serializable) {
+        // TODO: augment supported types to encode as an AmqpValue?
+        return serializable instanceof Map<?,?> ||
+               serializable instanceof List<?> ||
+               serializable.getClass().isArray();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
new file mode 100644
index 0000000..2f4db2c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProvider.java
@@ -0,0 +1,857 @@
+/**
+ * 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.jms.provider.failover;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsSslContext;
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.provider.DefaultProviderListener;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFactory;
+import org.apache.qpid.jms.provider.ProviderFuture;
+import org.apache.qpid.jms.provider.ProviderListener;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Provider Facade that provides services for detection dropped Provider connections
+ * and attempting to reconnect to a different remote peer.  Upon establishment of a new
+ * connection the FailoverProvider will initiate state recovery of the active JMS
+ * framework resources.
+ */
+public class FailoverProvider extends DefaultProviderListener implements Provider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FailoverProvider.class);
+
+    private static final int UNLIMITED = -1;
+
+    private ProviderListener listener;
+    private Provider provider;
+    private final FailoverUriPool uris;
+
+    private final ExecutorService serializer;
+    private final ScheduledExecutorService connectionHub;
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private final AtomicBoolean failed = new AtomicBoolean();
+    private final AtomicLong requestId = new AtomicLong();
+    private final Map<Long, FailoverRequest> requests = new LinkedHashMap<Long, FailoverRequest>();
+    private final DefaultProviderListener closedListener = new DefaultProviderListener();
+    private final JmsSslContext sslContext;
+    private final JmsMessageFactory defaultMessageFactory = new JmsDefaultMessageFactory();
+
+    // Current state of connection / reconnection
+    private boolean firstConnection = true;
+    private long reconnectAttempts;
+    private long reconnectDelay = TimeUnit.SECONDS.toMillis(5);
+    private IOException failureCause;
+    private URI connectedURI;
+
+    // Timeout values configured via JmsConnectionInfo
+    private long connectTimeout = JmsConnectionInfo.DEFAULT_CONNECT_TIMEOUT;
+    private long closeTimeout = JmsConnectionInfo.DEFAULT_CLOSE_TIMEOUT;
+    private long sendTimeout =  JmsConnectionInfo.DEFAULT_SEND_TIMEOUT;
+    private long requestTimeout = JmsConnectionInfo.DEFAULT_REQUEST_TIMEOUT;
+
+    // Configuration values.
+    private long initialReconnectDelay = 0L;
+    private long maxReconnectDelay = TimeUnit.SECONDS.toMillis(30);
+    private boolean useExponentialBackOff = true;
+    private double backOffMultiplier = 2d;
+    private int maxReconnectAttempts = UNLIMITED;
+    private int startupMaxReconnectAttempts = UNLIMITED;
+    private int warnAfterReconnectAttempts = 10;
+
+    public FailoverProvider(Map<String, String> nestedOptions) {
+        this(null, nestedOptions);
+    }
+
+    public FailoverProvider(URI[] uris) {
+        this(uris, null);
+    }
+
+    public FailoverProvider(URI[] uris, Map<String, String> nestedOptions) {
+        this.uris = new FailoverUriPool(uris, nestedOptions);
+        this.sslContext = JmsSslContext.getCurrentSslContext();
+
+        this.serializer = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
+
+            @Override
+            public Thread newThread(Runnable runner) {
+                Thread serial = new Thread(runner);
+                serial.setDaemon(true);
+                serial.setName("FailoverProvider: serialization thread");
+                return serial;
+            }
+        });
+
+        // All Connection attempts happen in this schedulers thread.  Once a connection
+        // is established it will hand the open connection back to the serializer thread
+        // for state recovery.
+        this.connectionHub = Executors.newScheduledThreadPool(1, new ThreadFactory() {
+
+            @Override
+            public Thread newThread(Runnable runner) {
+                Thread serial = new Thread(runner);
+                serial.setDaemon(true);
+                serial.setName("FailoverProvider: connect thread");
+                return serial;
+            }
+        });
+    }
+
+    @Override
+    public void connect() throws IOException {
+        checkClosed();
+        LOG.debug("Performing initial connection attempt");
+        triggerReconnectionAttempt();
+    }
+
+    @Override
+    public void start() throws IOException, IllegalStateException {
+        checkClosed();
+
+        if (listener == null) {
+            throw new IllegalStateException("No ProviderListener registered.");
+        }
+    }
+
+    @Override
+    public void close() {
+        if (closed.compareAndSet(false, true)) {
+            final ProviderFuture request = new ProviderFuture();
+            serializer.execute(new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+                        IOException error = failureCause != null ? failureCause : new IOException("Connection closed");
+                        List<FailoverRequest> pending = new ArrayList<FailoverRequest>(requests.values());
+                        for (FailoverRequest request : pending) {
+                            request.onFailure(error);
+                        }
+
+                        if (provider != null) {
+                            provider.close();
+                        }
+                    } catch (Exception e) {
+                        LOG.debug("Caught exception while closing connection");
+                    } finally {
+
+                        if (connectionHub != null) {
+                            connectionHub.shutdown();
+                        }
+
+                        if (serializer != null) {
+                            serializer.shutdown();
+                        }
+
+                        request.onSuccess();
+                    }
+                }
+            });
+
+            try {
+                if (this.closeTimeout >= 0) {
+                    request.sync();
+                } else {
+                    request.sync(closeTimeout, TimeUnit.MILLISECONDS);
+                }
+            } catch (IOException e) {
+                LOG.warn("Error caught while closing Provider: ", e.getMessage());
+            }
+        }
+    }
+
+    @Override
+    public void create(final JmsResource resource, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                if (resource instanceof JmsConnectionInfo) {
+                    JmsConnectionInfo connectionInfo = (JmsConnectionInfo) resource;
+                    connectTimeout = connectionInfo.getConnectTimeout();
+                    closeTimeout = connectionInfo.getCloseTimeout();
+                    sendTimeout = connectionInfo.getSendTimeout();
+                    requestTimeout = connectionInfo.getRequestTimeout();
+                }
+
+                provider.create(resource, this);
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void start(final JmsResource resource, final AsyncResult request) throws IOException, JMSException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.start(resource, this);
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void destroy(final JmsResource resourceId, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws IOException, JMSException, UnsupportedOperationException {
+                provider.destroy(resourceId, this);
+            }
+
+            @Override
+            public boolean succeedsWhenOffline() {
+                // Allow this to succeed, acks would be stale.
+                return true;
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void send(final JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.send(envelope, this);
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void acknowledge(final JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.acknowledge(sessionId, this);
+            }
+
+            @Override
+            public boolean succeedsWhenOffline() {
+                // Allow this to succeed, acks would be stale.
+                return true;
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void acknowledge(final JmsInboundMessageDispatch envelope, final ACK_TYPE ackType, AsyncResult request) throws IOException, JMSException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.acknowledge(envelope, ackType, this);
+            }
+
+            @Override
+            public boolean succeedsWhenOffline() {
+                // Allow this to succeed, acks would be stale.
+                return true;
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void commit(final JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.commit(sessionId, this);
+            }
+
+            @Override
+            public boolean failureWhenOffline() {
+                return true;
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void rollback(final JmsSessionId sessionId, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.rollback(sessionId, this);
+            }
+
+            @Override
+            public boolean failureWhenOffline() {
+                return true;
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+
+    @Override
+    public void recover(final JmsSessionId sessionId, final AsyncResult request) throws IOException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.recover(sessionId, this);
+            }
+
+            @Override
+            public boolean succeedsWhenOffline() {
+                return true;
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void unsubscribe(final String subscription, AsyncResult request) throws IOException, JMSException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.unsubscribe(subscription, this);
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public void pull(final JmsConsumerId consumerId, final long timeout, final AsyncResult request) throws IOException, UnsupportedOperationException {
+        checkClosed();
+        final FailoverRequest pending = new FailoverRequest(request) {
+            @Override
+            public void doTask() throws Exception {
+                provider.pull(consumerId, timeout, this);
+            }
+        };
+
+        serializer.execute(pending);
+    }
+
+    @Override
+    public JmsMessageFactory getMessageFactory() {
+        final AtomicReference<JmsMessageFactory> result =
+            new AtomicReference<JmsMessageFactory>(defaultMessageFactory);
+
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                if (provider != null) {
+                    result.set(provider.getMessageFactory());
+                }
+            }
+        });
+
+        return result.get();
+    }
+
+    //--------------- Connection Error and Recovery methods ------------------//
+
+    /**
+     * This method is always called from within the FailoverProvider's serialization thread.
+     *
+     * When a failure is encountered either from an outgoing request or from an error fired
+     * from the underlying Provider instance this method is called to determine if a reconnect
+     * is allowed and if so a new reconnect cycle is triggered on the connection thread.
+     *
+     * @param cause
+     */
+    private void handleProviderFailure(final IOException cause) {
+        LOG.debug("handling Provider failure: {}", cause.getMessage());
+        LOG.trace("stack", cause);
+
+        this.provider.setProviderListener(closedListener);
+        URI failedURI = this.provider.getRemoteURI();
+        try {
+            this.provider.close();
+        } catch (Throwable error) {
+            LOG.trace("Caught exception while closing failed provider: {}", error.getMessage());
+        }
+        this.provider = null;
+
+        if (reconnectAllowed()) {
+            ProviderListener listener = this.listener;
+            if (listener != null) {
+                listener.onConnectionInterrupted(failedURI);
+            }
+            triggerReconnectionAttempt();
+        } else {
+            ProviderListener listener = this.listener;
+            if (listener != null) {
+                listener.onConnectionFailure(cause);
+            }
+        }
+    }
+
+    /**
+     * Called from the reconnection thread.  This method enqueues a new task that
+     * will attempt to recover connection state, once successful normal operations
+     * will resume.  If an error occurs while attempting to recover the JMS framework
+     * state then a reconnect cycle is again triggered on the connection thread.
+     *
+     * @param provider
+     *        The newly connect Provider instance that will become active.
+     */
+    private void initializeNewConnection(final Provider provider) {
+        this.serializer.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (firstConnection) {
+                        firstConnection = false;
+                        FailoverProvider.this.provider = provider;
+                        provider.setProviderListener(FailoverProvider.this);
+
+                        List<FailoverRequest> pending = new ArrayList<FailoverRequest>(requests.values());
+                        for (FailoverRequest request : pending) {
+                            request.run();
+                        }
+                    } else {
+                        LOG.debug("Signalling connection recovery: {}", provider);
+                        FailoverProvider.this.provider = provider;
+                        provider.setProviderListener(FailoverProvider.this);
+
+                        // Stage 1: Recovery all JMS Framework resources
+                        listener.onConnectionRecovery(provider);
+
+                        // Stage 2: Restart consumers, send pull commands, etc.
+                        listener.onConnectionRecovered(provider);
+
+                        // Stage 3: Let the client know that connection has restored.
+                        listener.onConnectionRestored(provider.getRemoteURI());
+
+                        // Stage 4: Send pending actions.
+                        List<FailoverRequest> pending = new ArrayList<FailoverRequest>(requests.values());
+                        for (FailoverRequest request : pending) {
+                            request.run();
+                        }
+
+                        reconnectDelay = initialReconnectDelay;
+                        reconnectAttempts = 0;
+                        connectedURI = provider.getRemoteURI();
+                        uris.connected();
+                    }
+                } catch (Throwable error) {
+                    handleProviderFailure(IOExceptionSupport.create(error));
+                }
+            }
+        });
+    }
+
+    /**
+     * Called when the Provider was either first created or when a connection failure has
+     * been connected.  A reconnection attempt is immediately executed on the connection
+     * thread.  If a new Provider is able to be created and connected then a recovery task
+     * is scheduled on the main serializer thread.  If the connect attempt fails another
+     * attempt is scheduled based on the configured delay settings until a max attempts
+     * limit is hit, if one is set.
+     */
+    private void triggerReconnectionAttempt() {
+        if (closed.get() || failed.get()) {
+            return;
+        }
+
+        connectionHub.execute(new Runnable() {
+            @Override
+            public void run() {
+                if (provider != null || closed.get() || failed.get()) {
+                    return;
+                }
+
+                reconnectAttempts++;
+                Throwable failure = null;
+                URI target = uris.getNext();
+                if (target != null) {
+                    try {
+                        LOG.debug("Attempting connection to: {}", target);
+                        JmsSslContext.setCurrentSslContext(sslContext);
+                        Provider provider = ProviderFactory.createAsync(target);
+                        initializeNewConnection(provider);
+                        return;
+                    } catch (Throwable e) {
+                        LOG.info("Connection attempt to: {} failed.", target);
+                        failure = e;
+                    }
+                }
+
+                int reconnectLimit = reconnectAttemptLimit();
+
+                if (reconnectLimit != UNLIMITED && reconnectAttempts >= reconnectLimit) {
+                    LOG.error("Failed to connect after: " + reconnectAttempts + " attempt(s)");
+                    failed.set(true);
+                    failureCause = IOExceptionSupport.create(failure);
+                    if (listener != null) {
+                        listener.onConnectionFailure(failureCause);
+                    };
+
+                    return;
+                }
+
+                int warnInterval = getWarnAfterReconnectAttempts();
+                if (warnInterval > 0 && (reconnectAttempts % warnInterval) == 0) {
+                    LOG.warn("Failed to connect after: {} attempt(s) continuing to retry.", reconnectAttempts);
+                }
+
+                long delay = nextReconnectDelay();
+                connectionHub.schedule(this, delay, TimeUnit.MILLISECONDS);
+            }
+        });
+    }
+
+    private boolean reconnectAllowed() {
+        return reconnectAttemptLimit() != 0;
+    }
+
+    private int reconnectAttemptLimit() {
+        int maxReconnectValue = this.maxReconnectAttempts;
+        if (firstConnection && this.startupMaxReconnectAttempts != UNLIMITED) {
+            maxReconnectValue = this.startupMaxReconnectAttempts;
+        }
+        return maxReconnectValue;
+    }
+
+    private long nextReconnectDelay() {
+        if (useExponentialBackOff) {
+            // Exponential increment of reconnect delay.
+            reconnectDelay *= backOffMultiplier;
+            if (reconnectDelay > maxReconnectDelay) {
+                reconnectDelay = maxReconnectDelay;
+            }
+        }
+
+        return reconnectDelay;
+    }
+
+    protected void checkClosed() throws IOException {
+        if (closed.get()) {
+            throw new IOException("The Provider is already closed");
+        }
+    }
+
+    //--------------- DefaultProviderListener overrides ----------------------//
+
+    @Override
+    public void onMessage(final JmsInboundMessageDispatch envelope) {
+        if (closed.get() || failed.get()) {
+            return;
+        }
+        serializer.execute(new Runnable() {
+            @Override
+            public void run() {
+                if (!closed.get()) {
+                    listener.onMessage(envelope);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void onConnectionFailure(final IOException ex) {
+        if (closed.get() || failed.get()) {
+            return;
+        }
+        serializer.execute(new Runnable() {
+            @Override
+            public void run() {
+                if (!closed.get() && !failed.get()) {
+                    LOG.debug("Failover: the provider reports failure: {}", ex.getMessage());
+                    handleProviderFailure(ex);
+                }
+            }
+        });
+    }
+
+    //--------------- URI update and rebalance methods -----------------------//
+
+    public void add(final URI uri) {
+        serializer.execute(new Runnable() {
+            @Override
+            public void run() {
+                uris.add(uri);
+            }
+        });
+    }
+
+    public void remove(final URI uri) {
+        serializer.execute(new Runnable() {
+            @Override
+            public void run() {
+                uris.remove(uri);
+            }
+        });
+    }
+
+    //--------------- Property Getters and Setters ---------------------------//
+
+    @Override
+    public URI getRemoteURI() {
+        Provider provider = this.provider;
+        if (provider != null) {
+            return provider.getRemoteURI();
+        }
+        return null;
+    }
+
+    @Override
+    public void setProviderListener(ProviderListener listener) {
+        this.listener = listener;
+    }
+
+    @Override
+    public ProviderListener getProviderListener() {
+        return listener;
+    }
+
+    public boolean isRandomize() {
+        return uris.isRandomize();
+    }
+
+    public void setRandomize(boolean value) {
+        this.uris.setRandomize(value);
+    }
+
+    public long getInitialReconnectDealy() {
+        return initialReconnectDelay;
+    }
+
+    public void setInitialReconnectDealy(long initialReconnectDealy) {
+        this.initialReconnectDelay = initialReconnectDealy;
+    }
+
+    public long getMaxReconnectDelay() {
+        return maxReconnectDelay;
+    }
+
+    public void setMaxReconnectDelay(long maxReconnectDelay) {
+        this.maxReconnectDelay = maxReconnectDelay;
+    }
+
+    public int getMaxReconnectAttempts() {
+        return maxReconnectAttempts;
+    }
+
+    public void setMaxReconnectAttempts(int maxReconnectAttempts) {
+        this.maxReconnectAttempts = maxReconnectAttempts;
+    }
+
+    public int getStartupMaxReconnectAttempts() {
+        return startupMaxReconnectAttempts;
+    }
+
+    public void setStartupMaxReconnectAttempts(int startupMaxReconnectAttempts) {
+        this.startupMaxReconnectAttempts = startupMaxReconnectAttempts;
+    }
+
+    /**
+     * Gets the current setting controlling how many Connect / Reconnect attempts must occur
+     * before a warn message is logged.  A value of {@code <= 0} indicates that there will be
+     * no warn message logged regardless of how many reconnect attempts occur.
+     *
+     * @return the current number of connection attempts before warn logging is triggered.
+     */
+    public int getWarnAfterReconnectAttempts() {
+        return warnAfterReconnectAttempts;
+    }
+
+    /**
+     * Sets the number of Connect / Reconnect attempts that must occur before a warn message
+     * is logged indicating that the transport is not connected.  This can be useful when the
+     * client is running inside some container or service as it gives an indication of some
+     * problem with the client connection that might not otherwise be visible.  To disable the
+     * log messages this value should be set to a value @{code attempts <= 0}
+     *
+     * @param warnAfterReconnectAttempts
+     *        The number of failed connection attempts that must happen before a warning is logged.
+     */
+    public void setWarnAfterReconnectAttempts(int warnAfterReconnectAttempts) {
+        this.warnAfterReconnectAttempts = warnAfterReconnectAttempts;
+    }
+
+    public double getReconnectDelayExponent() {
+        return backOffMultiplier;
+    }
+
+    public void setReconnectDelayExponent(double reconnectDelayExponent) {
+        this.backOffMultiplier = reconnectDelayExponent;
+    }
+
+    public boolean isUseExponentialBackOff() {
+        return useExponentialBackOff;
+    }
+
+    public void setUseExponentialBackOff(boolean useExponentialBackOff) {
+        this.useExponentialBackOff = useExponentialBackOff;
+    }
+
+    public long getConnectTimeout() {
+        return this.connectTimeout;
+    }
+
+    public long getCloseTimeout() {
+        return this.closeTimeout;
+    }
+
+    public long getSendTimeout() {
+        return this.sendTimeout;
+    }
+
+    public long getRequestTimeout() {
+        return this.requestTimeout;
+    }
+
+    @Override
+    public String toString() {
+        return "FailoverProvider: " +
+               (connectedURI == null ? "unconnected" : connectedURI.toString());
+    }
+
+    //--------------- FailoverProvider Asynchronous Request --------------------//
+
+    /**
+     * For all requests that are dispatched from the FailoverProvider to a connected
+     * Provider instance an instance of FailoverRequest is used to handle errors that
+     * occur during processing of that request and trigger a reconnect.
+     *
+     * @param <T>
+     */
+    protected abstract class FailoverRequest extends ProviderFuture implements Runnable {
+
+        private final long id = requestId.incrementAndGet();
+
+        public FailoverRequest(AsyncResult watcher) {
+            super(watcher);
+        }
+
+        @Override
+        public void run() {
+            requests.put(id, this);
+            if (provider == null) {
+                if (failureWhenOffline()) {
+                    requests.remove(id);
+                    watcher.onFailure(new IOException("Provider disconnected"));
+                } else if (succeedsWhenOffline()) {
+                    onSuccess();
+                }
+            } else {
+                try {
+                    LOG.debug("Executing Failover Task: {}", this);
+                    doTask();
+                } catch (UnsupportedOperationException e) {
+                    requests.remove(id);
+                    watcher.onFailure(e);
+                } catch (Exception e) {
+                    // TODO Should we let JMSException through?
+                    LOG.debug("Caught exception while executing task: {}", e.getMessage());
+                    triggerReconnectionAttempt();
+                }
+            }
+        }
+
+        @Override
+        public void onFailure(final Throwable result) {
+            if (closed.get() || failed.get()) {
+                requests.remove(id);
+                super.onFailure(result);
+            } else {
+                LOG.debug("Request received error: {}", result.getMessage());
+                serializer.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        handleProviderFailure(IOExceptionSupport.create(result));
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onSuccess() {
+            requests.remove(id);
+            super.onSuccess();
+        }
+
+        /**
+         * Called to execute the specific task that was requested.
+         *
+         * @throws Exception if an error occurs during task execution.
+         */
+        public abstract void doTask() throws Exception;
+
+        /**
+         * Should the request just succeed when the Provider is not connected.
+         *
+         * @return true if the request is marked as successful when not connected.
+         */
+        public boolean succeedsWhenOffline() {
+            return false;
+        }
+
+        /**
+         * When the transport is not connected should this request automatically fail.
+         *
+         * @return true if the task should fail when the Provider is not connected.
+         */
+        public boolean failureWhenOffline() {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProviderFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProviderFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProviderFactory.java
new file mode 100644
index 0000000..8c63869
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverProviderFactory.java
@@ -0,0 +1,56 @@
+/**
+ * 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.jms.provider.failover;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFactory;
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+import org.apache.qpid.jms.util.URISupport.CompositeData;
+
+/**
+ * Factory for creating instances of the Failover Provider type.
+ */
+public class FailoverProviderFactory extends ProviderFactory {
+
+    @Override
+    public Provider createAsyncProvider(URI remoteURI) throws Exception {
+        CompositeData composite = URISupport.parseComposite(remoteURI);
+        Map<String, String> options = composite.getParameters();
+        Map<String, String> nested = PropertyUtil.filterProperties(options, "nested.");
+
+        FailoverProvider provider = new FailoverProvider(composite.getComponents(), nested);
+        if (!PropertyUtil.setProperties(provider, options)) {
+            String msg = ""
+                + " Not all options could be set on the Failover provider."
+                + " Check the options are spelled correctly."
+                + " Given parameters=[" + options + "]."
+                + " This Provider cannot be started.";
+            throw new IllegalArgumentException(msg);
+        }
+
+        return provider;
+    }
+
+    @Override
+    public String getName() {
+        return "Failover";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverUriPool.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverUriPool.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverUriPool.java
new file mode 100644
index 0000000..bb2d2b3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/failover/FailoverUriPool.java
@@ -0,0 +1,196 @@
+/**
+ * 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.jms.provider.failover;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.apache.qpid.jms.util.URISupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the list of available failover URIs that are used to connect
+ * and recover a connection.
+ */
+public class FailoverUriPool {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FailoverUriPool.class);
+
+    private final LinkedList<URI> uris;
+    private final Map<String, String> nestedOptions;
+    private boolean randomize;
+
+    public FailoverUriPool() {
+        this.uris = new LinkedList<URI>();
+        this.nestedOptions = Collections.emptyMap();
+    }
+
+    public FailoverUriPool(URI[] uris, Map<String, String> nestedOptions) {
+        this.uris = new LinkedList<URI>();
+        if (nestedOptions != null) {
+            this.nestedOptions = nestedOptions;
+        } else {
+            this.nestedOptions = Collections.emptyMap();
+        }
+
+        if (uris != null) {
+            for (URI uri : uris) {
+                this.add(uri);
+            }
+        }
+    }
+
+    /**
+     * Returns the next URI in the pool of URIs.  The URI will be shifted to the
+     * end of the list and not be attempted again until the full list has been
+     * returned once.
+     *
+     * @return the next URI that should be used for a connection attempt.
+     */
+    public URI getNext() {
+        URI next = null;
+        if (!uris.isEmpty()) {
+            next = uris.removeFirst();
+            uris.addLast(next);
+        }
+
+        return next;
+    }
+
+    /**
+     * Reports that the Failover Provider connected to the last URI returned from
+     * this pool.  If the Pool is set to randomize this will result in the Pool of
+     * URIs being shuffled in preparation for the next connect cycle.
+     */
+    public void connected() {
+        if (isRandomize()) {
+            Collections.shuffle(uris);
+        }
+    }
+
+    /**
+     * @return true if this pool returns the URI values in random order.
+     */
+    public boolean isRandomize() {
+        return randomize;
+    }
+
+    /**
+     * Sets whether the URIs that are returned by this pool are returned in random
+     * order or not.  If false the URIs are returned in FIFO order.
+     *
+     * @param randomize
+     *        true to have the URIs returned in a random order.
+     */
+    public void setRandomize(boolean randomize) {
+        this.randomize = randomize;
+        if (randomize) {
+            Collections.shuffle(uris);
+        }
+    }
+
+    /**
+     * Adds a new URI to the pool if not already contained within.  The URI will have
+     * any nest options that have been configured added to its existing set of options.
+     *
+     * @param uri
+     *        The new URI to add to the pool.
+     */
+    public void add(URI uri) {
+        if (!contains(uri)) {
+            if (!nestedOptions.isEmpty()) {
+                try {
+                    URISupport.applyParameters(uri, nestedOptions);
+                } catch (URISyntaxException e) {
+                    LOG.debug("Failed to add nested options to uri: {}", uri);
+                }
+            }
+
+            this.uris.add(uri);
+        }
+    }
+
+    /**
+     * Remove a URI from the pool if present, otherwise has no effect.
+     *
+     * @param uri
+     *        The URI to attempt to remove from the pool.
+     */
+    public void remove(URI uri) {
+        this.uris.remove(uri);
+    }
+
+    /**
+     * Returns the currently set value for nested options which will be added to each
+     * URI that is returned from the pool.
+     *
+     * @return the Map instance containing the nest options which can be empty if none set.
+     */
+    public Map<String, String> getNestedOptions() {
+        return nestedOptions;
+    }
+
+    private boolean contains(URI newURI) {
+        boolean result = false;
+        for (URI uri : uris) {
+            if (compareURIs(newURI, uri)) {
+                result = true;
+                break;
+            }
+        }
+
+        return result;
+    }
+
+    private boolean compareURIs(final URI first, final URI second) {
+        boolean result = false;
+        if (first == null || second == null) {
+            return result;
+        }
+
+        if (first.getPort() == second.getPort()) {
+            InetAddress firstAddr = null;
+            InetAddress secondAddr = null;
+            try {
+                firstAddr = InetAddress.getByName(first.getHost());
+                secondAddr = InetAddress.getByName(second.getHost());
+
+                if (firstAddr.equals(secondAddr)) {
+                    result = true;
+                }
+            } catch(IOException e) {
+                if (firstAddr == null) {
+                    LOG.error("Failed to Lookup INetAddress for URI[ " + first + " ] : " + e);
+                } else {
+                    LOG.error("Failed to Lookup INetAddress for URI[ " + second + " ] : " + e);
+                }
+
+                if (first.getHost().equalsIgnoreCase(second.getHost())) {
+                    result = true;
+                }
+            }
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
new file mode 100644
index 0000000..d1972cd
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AbstractMechanism.java
@@ -0,0 +1,75 @@
+/**
+ * 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.jms.sasl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Base class for SASL Authentication Mechanism that implements the basic
+ * methods of a Mechanism class.
+ */
+public abstract class AbstractMechanism implements Mechanism {
+
+    protected static final byte[] EMPTY = new byte[0];
+
+    private String username;
+    private String password;
+    private Map<String, Object> properties = new HashMap<String, Object>();
+
+    @Override
+    public int compareTo(Mechanism other) {
+
+        if (getPriority() < other.getPriority()) {
+            return -1;
+        } else if (getPriority() > other.getPriority()) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+    @Override
+    public void setUsername(String value) {
+        this.username = value;
+    }
+
+    @Override
+    public String getUsername() {
+        return username;
+    }
+
+    @Override
+    public void setPassword(String value) {
+        this.password = value;
+    }
+
+    @Override
+    public String getPassword() {
+        return this.password;
+    }
+
+    @Override
+    public void setProperties(Map<String, Object> properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public Map<String, Object> getProperties() {
+        return this.properties;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
new file mode 100644
index 0000000..903a5fe
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanism.java
@@ -0,0 +1,43 @@
+/**
+ * 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.jms.sasl;
+
+/**
+ * Implements the Anonymous SASL authentication mechanism.
+ */
+public class AnonymousMechanism extends AbstractMechanism {
+
+    @Override
+    public byte[] getInitialResponse() {
+        return EMPTY;
+    }
+
+    @Override
+    public byte[] getChallengeResponse(byte[] challenge) {
+        return EMPTY;
+    }
+
+    @Override
+    public int getPriority() {
+        return PRIORITY.LOWEST.getValue();
+    }
+
+    @Override
+    public String getName() {
+        return "ANONYMOUS";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanismFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanismFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanismFactory.java
new file mode 100644
index 0000000..28cd1f1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/AnonymousMechanismFactory.java
@@ -0,0 +1,28 @@
+/**
+ * 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.jms.sasl;
+
+/**
+ * Create the Anonymous SASL Authentication Mechanism types.
+ */
+public class AnonymousMechanismFactory implements MechanismFactory {
+
+    @Override
+    public Mechanism createMechanism() {
+        return new AnonymousMechanism();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
new file mode 100644
index 0000000..4b896ce
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5Mechanism.java
@@ -0,0 +1,86 @@
+/**
+ * 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.jms.sasl;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.security.sasl.SaslException;
+
+/**
+ * Implements the SASL PLAIN authentication Mechanism.
+ *
+ * User name and Password values are sent without being encrypted.
+ */
+public class CramMD5Mechanism extends AbstractMechanism {
+
+    private static final String ASCII = "ASCII";
+    private static final String HMACMD5 = "HMACMD5";
+    private boolean _sentResponse;
+
+    @Override
+    public int getPriority() {
+        return PRIORITY.HIGH.getValue();
+    }
+
+    @Override
+    public String getName() {
+        return "CRAM-MD5";
+    }
+
+    @Override
+    public byte[] getInitialResponse() {
+        return EMPTY;
+    }
+
+    @Override
+    public byte[] getChallengeResponse(byte[] challenge) throws SaslException {
+        if (!_sentResponse && challenge != null && challenge.length != 0) {
+            try {
+                SecretKeySpec key = new SecretKeySpec(getPassword().getBytes(ASCII), HMACMD5);
+                Mac mac = Mac.getInstance(HMACMD5);
+                mac.init(key);
+
+                byte[] bytes = mac.doFinal(challenge);
+
+                StringBuffer hash = new StringBuffer(getUsername());
+                hash.append(' ');
+                for (int i = 0; i < bytes.length; i++) {
+                    String hex = Integer.toHexString(0xFF & bytes[i]);
+                    if (hex.length() == 1) {
+                        hash.append('0');
+                    }
+                    hash.append(hex);
+                }
+
+                _sentResponse = true;
+                return hash.toString().getBytes(ASCII);
+            } catch (UnsupportedEncodingException e) {
+                throw new SaslException("Unable to utilise required encoding", e);
+            } catch (InvalidKeyException e) {
+                throw new SaslException("Unable to utilise key", e);
+            } catch (NoSuchAlgorithmException e) {
+                throw new SaslException("Unable to utilise required algorithm", e);
+            }
+        } else {
+            return EMPTY;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5MechanismFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5MechanismFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5MechanismFactory.java
new file mode 100644
index 0000000..0ce5736
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/CramMD5MechanismFactory.java
@@ -0,0 +1,28 @@
+/**
+ * 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.jms.sasl;
+
+/**
+ * Create the Plain SASL Authentication Mechanism types.
+ */
+public class CramMD5MechanismFactory implements MechanismFactory {
+
+    @Override
+    public Mechanism createMechanism() {
+        return new CramMD5Mechanism();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
new file mode 100644
index 0000000..4fbfcd5
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/Mechanism.java
@@ -0,0 +1,125 @@
+/**
+ * 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.jms.sasl;
+
+import java.util.Map;
+
+import javax.security.sasl.SaslException;
+
+/**
+ * Interface for all SASL authentication mechanism implementations.
+ */
+public interface Mechanism extends Comparable<Mechanism> {
+
+    /**
+     * Relative priority values used to arrange the found SASL
+     * mechanisms in a preferred order where the level of security
+     * generally defines the preference.
+     */
+    public enum PRIORITY {
+        LOWEST(0),
+        LOW(1),
+        MEDIUM(2),
+        HIGH(3),
+        HIGHEST(4);
+
+        private final int value;
+
+        private PRIORITY(int value) {
+            this.value = value;
+        }
+
+        public int getValue() {
+            return value;
+       }
+    };
+
+    /**
+     * @return return the relative priority of this SASL mechanism.
+     */
+    int getPriority();
+
+    /**
+     * @return the well known name of this SASL mechanism.
+     */
+    String getName();
+
+    /**
+     * @return the response buffer used to answer the initial SASL cycle.
+     * @throws SaslException if an error occurs computing the response.
+     */
+    byte[] getInitialResponse() throws SaslException;
+
+    /**
+     * Create a response based on a given challenge from the remote peer.
+     *
+     * @param challenge
+     *        the challenge that this Mechanism should response to.
+     *
+     * @return the response that answers the given challenge.
+     * @throws SaslException if an error occurs computing the response.
+     */
+    byte[] getChallengeResponse(byte[] challenge) throws SaslException;
+
+    /**
+     * Sets the user name value for this Mechanism.  The Mechanism can ignore this
+     * value if it does not utilize user name in it's authentication processing.
+     *
+     * @param username
+     *        The user name given.
+     */
+    void setUsername(String value);
+
+    /**
+     * Returns the configured user name value for this Mechanism.
+     *
+     * @return the currently set user name value for this Mechanism.
+     */
+    String getUsername();
+
+    /**
+     * Sets the password value for this Mechanism.  The Mechanism can ignore this
+     * value if it does not utilize a password in it's authentication processing.
+     *
+     * @param username
+     *        The user name given.
+     */
+    void setPassword(String value);
+
+    /**
+     * Returns the configured password value for this Mechanism.
+     *
+     * @return the currently set password value for this Mechanism.
+     */
+    String getPassword();
+
+    /**
+     * Sets any additional Mechanism specific properties using a Map<String, Object>
+     *
+     * @param options
+     *        the map of additional properties that this Mechanism should utilize.
+     */
+    void setProperties(Map<String, Object> options);
+
+    /**
+     * The currently set Properties for this Mechanism.
+     *
+     * @return the current set of configuration Properties for this Mechanism.
+     */
+    Map<String, Object> getProperties();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/MechanismFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/MechanismFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/MechanismFactory.java
new file mode 100644
index 0000000..a47f38c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/MechanismFactory.java
@@ -0,0 +1,31 @@
+/**
+ * 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.jms.sasl;
+
+/**
+ * Interface for all SASL authentication mechanism implementations.
+ */
+public interface MechanismFactory {
+
+    /**
+     * Creates an instance of the authentication mechanism implementation.
+     *
+     * @return a new Mechanism instance.
+     */
+    Mechanism createMechanism();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
new file mode 100644
index 0000000..b305e98
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanism.java
@@ -0,0 +1,62 @@
+/**
+ * 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.jms.sasl;
+
+/**
+ * Implements the SASL PLAIN authentication Mechanism.
+ *
+ * User name and Password values are sent without being encrypted.
+ */
+public class PlainMechanism extends AbstractMechanism {
+
+    @Override
+    public int getPriority() {
+        return PRIORITY.MEDIUM.getValue();
+    }
+
+    @Override
+    public String getName() {
+        return "PLAIN";
+    }
+
+    @Override
+    public byte[] getInitialResponse() {
+
+        String username = getUsername();
+        String password = getPassword();
+
+        if (username == null) {
+            username = "";
+        }
+
+        if (password == null) {
+            password = "";
+        }
+
+        byte[] usernameBytes = username.getBytes();
+        byte[] passwordBytes = password.getBytes();
+        byte[] data = new byte[usernameBytes.length + passwordBytes.length + 2];
+        System.arraycopy(usernameBytes, 0, data, 1, usernameBytes.length);
+        System.arraycopy(passwordBytes, 0, data, 2 + usernameBytes.length, passwordBytes.length);
+        return data;
+    }
+
+    @Override
+    public byte[] getChallengeResponse(byte[] challenge) {
+        return EMPTY;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanismFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanismFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanismFactory.java
new file mode 100644
index 0000000..3cdd205
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/PlainMechanismFactory.java
@@ -0,0 +1,28 @@
+/**
+ * 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.jms.sasl;
+
+/**
+ * Create the Plain SASL Authentication Mechanism types.
+ */
+public class PlainMechanismFactory implements MechanismFactory {
+
+    @Override
+    public Mechanism createMechanism() {
+        return new PlainMechanism();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
new file mode 100644
index 0000000..5bc0a94
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/sasl/SaslMechanismFinder.java
@@ -0,0 +1,108 @@
+/**
+ * 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.jms.sasl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.qpid.jms.util.FactoryFinder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used to find a SASL Mechanism that most closely matches the preferred set
+ * of Mechanisms supported by the remote peer.
+ *
+ * The Matching mechanism is chosen by first find all instances of SASL
+ * mechanism types that are supported on the remote peer, and then making a
+ * final selection based on the Mechanism in the found set that has the
+ * highest priority value.
+ */
+public class SaslMechanismFinder {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SaslMechanismFinder.class);
+
+    private static final FactoryFinder<MechanismFactory> MECHANISM_FACTORY_FINDER =
+        new FactoryFinder<MechanismFactory>(MechanismFactory.class,
+            "META-INF/services/" + SaslMechanismFinder.class.getPackage().getName().replace(".", "/") + "/");
+
+    /**
+     * Attempts to find a matching Mechanism implementation given a list of supported
+     * mechanisms from a remote peer.  Can return null if no matching Mechanisms are
+     * found.
+     *
+     * @param remoteMechanisms
+     *        list of mechanism names that are supported by the remote peer.
+     *
+     * @return the best matching Mechanism for the supported remote set.
+     */
+    public static Mechanism findMatchingMechanism(String...remoteMechanisms) {
+
+        Mechanism match = null;
+        List<Mechanism> found = new ArrayList<Mechanism>();
+
+        for (String remoteMechanism : remoteMechanisms) {
+            try {
+                MechanismFactory factory = findMechanismFactory(remoteMechanism);
+                found.add(factory.createMechanism());
+            } catch (IOException e) {
+                LOG.warn("Caught exception while searching for SASL mechanisms: {}", e.getMessage());
+            }
+        }
+
+        if (!found.isEmpty()) {
+            // Sorts by priority using Mechanism comparison and return the last value in
+            // list which is the Mechanism deemed to be the highest priority match.
+            Collections.sort(found);
+            match = found.get(found.size() - 1);
+        }
+
+        LOG.info("Best match for SASL auth was: {}", match);
+
+        return match;
+    }
+
+    /**
+     * Searches for a MechanismFactory by using the scheme from the given name.
+     *
+     * The search first checks the local cache of mechanism factories before moving on
+     * to search in the classpath.
+     *
+     * @param name
+     *        The name of the authentication mechanism to search for..
+     *
+     * @return a mechanism factory instance matching the URI's scheme.
+     *
+     * @throws IOException if an error occurs while locating the factory.
+     */
+    protected static MechanismFactory findMechanismFactory(String name) throws IOException {
+        if (name == null || name.isEmpty()) {
+            throw new IOException("No Mechanism name specified: [" + name + "]");
+        }
+
+        MechanismFactory factory = null;
+        try {
+            factory = MECHANISM_FACTORY_FINDER.newInstance(name);
+        } catch (Throwable e) {
+            throw new IOException("Mechanism scheme NOT recognized: [" + name + "]", e);
+        }
+
+        return factory;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/RawTcpTransport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/RawTcpTransport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/RawTcpTransport.java
new file mode 100644
index 0000000..ae96ed7
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/RawTcpTransport.java
@@ -0,0 +1,383 @@
+/**
+ * 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.jms.transports;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.net.SocketFactory;
+
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.jms.util.InetAddressUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vertx.java.core.buffer.Buffer;
+
+/**
+ *
+ */
+public class RawTcpTransport implements Transport, Runnable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RawTcpTransport.class);
+
+    private TransportListener listener;
+    private final URI remoteLocation;
+    private final AtomicBoolean connected = new AtomicBoolean();
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private final AtomicReference<Throwable> connectionError = new AtomicReference<Throwable>();
+
+    private final Socket socket;
+    private DataOutputStream dataOut;
+    private DataInputStream dataIn;
+    private Thread runner;
+
+    private boolean closeAsync = true;
+    private int socketBufferSize = 64 * 1024;
+    private int soTimeout = 0;
+    private int soLinger = Integer.MIN_VALUE;
+    private Boolean keepAlive;
+    private Boolean tcpNoDelay = true;
+    private boolean useLocalHost = false;
+    private int ioBufferSize = 8 * 1024;
+
+    /**
+     * Create a new instance of the transport.
+     *
+     * @param listener
+     *        The TransportListener that will receive data from this Transport instance.
+     * @param remoteLocation
+     *        The remote location where this transport should connection to.
+     */
+    public RawTcpTransport(TransportListener listener, URI remoteLocation) {
+        this.listener = listener;
+        this.remoteLocation = remoteLocation;
+
+        Socket temp = null;
+        try {
+            temp = createSocketFactory().createSocket();
+        } catch (IOException e) {
+            connectionError.set(e);
+        }
+
+        this.socket = temp;
+    }
+
+    @Override
+    public void connect() throws IOException {
+        if (connectionError.get() != null) {
+            throw IOExceptionSupport.create(connectionError.get());
+        }
+
+        if (socket == null) {
+            throw new IllegalStateException("Cannot connect if the socket or socketFactory have not been set");
+        }
+
+        InetSocketAddress remoteAddress = null;
+
+        if (remoteLocation != null) {
+            String host = resolveHostName(remoteLocation.getHost());
+            remoteAddress = new InetSocketAddress(host, remoteLocation.getPort());
+        }
+
+        socket.connect(remoteAddress);
+
+        connected.set(true);
+
+        initialiseSocket(socket);
+        initializeStreams();
+
+        runner = new Thread(null, this, "QpidJMS RawTcpTransport: " + toString());
+        runner.setDaemon(false);
+        runner.start();
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (closed.compareAndSet(false, true)) {
+            if (socket == null) {
+                return;
+            }
+
+            // Closing the streams flush the sockets before closing.. if the socket
+            // is hung.. then this hangs the close so we support an asynchronous close
+            // by default which will timeout if the close doesn't happen after a delay.
+            if (closeAsync) {
+                final CountDownLatch latch = new CountDownLatch(1);
+
+                final ExecutorService closer = Executors.newSingleThreadExecutor();
+                closer.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        LOG.trace("Closing socket {}", socket);
+                        try {
+                            socket.close();
+                            LOG.debug("Closed socket {}", socket);
+                        } catch (IOException e) {
+                            if (LOG.isDebugEnabled()) {
+                                LOG.debug("Caught exception closing socket " + socket + ". This exception will be ignored.", e);
+                            }
+                        } finally {
+                            latch.countDown();
+                        }
+                    }
+                });
+
+                try {
+                    latch.await(1,TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                } finally {
+                    closer.shutdownNow();
+                }
+            } else {
+                LOG.trace("Closing socket {}", socket);
+                try {
+                    socket.close();
+                    LOG.debug("Closed socket {}", socket);
+                } catch (IOException e) {
+                    LOG.debug("Caught exception closing socket {}. This exception will be ignored.", socket, e);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void send(ByteBuffer output) throws IOException {
+        checkConnected();
+        LOG.info("RawTcpTransport sending packet of size: {}", output.remaining());
+        if (dataOut instanceof OutputStream) {
+            WritableByteChannel channel = Channels.newChannel(dataOut);
+            channel.write(output);
+        } else {
+            while (output.hasRemaining()) {
+                dataOut.writeByte(output.get());
+            }
+        }
+        dataOut.flush();
+    }
+
+    @Override
+    public void send(org.fusesource.hawtbuf.Buffer output) throws IOException {
+        checkConnected();
+        send(output.toByteBuffer());
+    }
+
+    @Override
+    public boolean isConnected() {
+        return this.connected.get();
+    }
+
+    @Override
+    public TransportListener getTransportListener() {
+        return this.listener;
+    }
+
+    @Override
+    public void setTransportListener(TransportListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener cannot be set to null");
+        }
+
+        this.listener = listener;
+    }
+
+    public int getSocketBufferSize() {
+        return socketBufferSize;
+    }
+
+    public void setSocketBufferSize(int socketBufferSize) {
+        this.socketBufferSize = socketBufferSize;
+    }
+
+    public int getSoTimeout() {
+        return soTimeout;
+    }
+
+    public void setSoTimeout(int soTimeout) {
+        this.soTimeout = soTimeout;
+    }
+
+    public boolean isTcpNoDelay() {
+        return tcpNoDelay;
+    }
+
+    public void setTcpNoDelay(Boolean tcpNoDelay) {
+        this.tcpNoDelay = tcpNoDelay;
+    }
+
+    public int getSoLinger() {
+        return soLinger;
+    }
+
+    public void setSoLinger(int soLinger) {
+        this.soLinger = soLinger;
+    }
+
+    public boolean isKeepAlive() {
+        return keepAlive;
+    }
+
+    public void setKeepAlive(Boolean keepAlive) {
+        this.keepAlive = keepAlive;
+    }
+
+    public boolean isUseLocalHost() {
+        return useLocalHost;
+    }
+
+    public void setUseLocalHost(boolean useLocalHost) {
+        this.useLocalHost = useLocalHost;
+    }
+
+    public int getIoBufferSize() {
+        return ioBufferSize;
+    }
+
+    public void setIoBufferSize(int ioBufferSize) {
+        this.ioBufferSize = ioBufferSize;
+    }
+
+    public boolean isCloseAsync() {
+        return closeAsync;
+    }
+
+    public void setCloseAsync(boolean closeAsync) {
+        this.closeAsync = closeAsync;
+    }
+
+    //---------- Transport internal implementation ---------------------------//
+
+    @Override
+    public void run() {
+        LOG.trace("TCP consumer thread for " + this + " starting");
+        try {
+            while (isConnected()) {
+                doRun();
+            }
+        } catch (IOException e) {
+            connectionError.set(e);
+            onException(e);
+        } catch (Throwable e) {
+            IOException ioe = new IOException("Unexpected error occured: " + e);
+            connectionError.set(ioe);
+            ioe.initCause(e);
+            onException(ioe);
+        }
+    }
+
+    protected void doRun() throws IOException {
+        int size = dataIn.available();
+        if (size <= 0) {
+            try {
+                TimeUnit.NANOSECONDS.sleep(1);
+            } catch (InterruptedException e) {
+            }
+            return;
+        }
+
+        byte[] buffer = new byte[size];
+        dataIn.readFully(buffer);
+        Buffer incoming = new Buffer(buffer);
+        listener.onData(incoming);
+    }
+
+    /**
+     * Passes any IO exceptions into the transport listener
+     */
+    public void onException(IOException e) {
+        if (listener != null) {
+            try {
+                listener.onTransportError(e);
+            } catch (RuntimeException e2) {
+                LOG.debug("Unexpected runtime exception: " + e2, e2);
+            }
+        }
+    }
+
+    protected SocketFactory createSocketFactory() throws IOException {
+        return SocketFactory.getDefault();
+    }
+
+    protected void initialiseSocket(Socket sock) throws SocketException, IllegalArgumentException {
+        try {
+            sock.setReceiveBufferSize(socketBufferSize);
+            sock.setSendBufferSize(socketBufferSize);
+        } catch (SocketException se) {
+            LOG.warn("Cannot set socket buffer size = {}", socketBufferSize);
+            LOG.debug("Cannot set socket buffer size. Reason: {}. This exception is ignored.", se.getMessage(), se);
+        }
+
+        sock.setSoTimeout(soTimeout);
+
+        if (keepAlive != null) {
+            sock.setKeepAlive(keepAlive.booleanValue());
+        }
+
+        if (soLinger > -1) {
+            sock.setSoLinger(true, soLinger);
+        } else if (soLinger == -1) {
+            sock.setSoLinger(false, 0);
+        }
+
+        if (tcpNoDelay != null) {
+            sock.setTcpNoDelay(tcpNoDelay.booleanValue());
+        }
+    }
+
+    protected void initializeStreams() throws IOException {
+        try {
+            TcpBufferedInputStream buffIn = new TcpBufferedInputStream(socket.getInputStream(), ioBufferSize);
+            this.dataIn = new DataInputStream(buffIn);
+            TcpBufferedOutputStream outputStream = new TcpBufferedOutputStream(socket.getOutputStream(), ioBufferSize);
+            this.dataOut = new DataOutputStream(outputStream);
+        } catch (Throwable e) {
+            throw IOExceptionSupport.create(e);
+        }
+    }
+
+    protected String resolveHostName(String host) throws UnknownHostException {
+        if (isUseLocalHost()) {
+            String localName = InetAddressUtil.getLocalHostName();
+            if (localName != null && localName.equals(host)) {
+                return "localhost";
+            }
+        }
+        return host;
+    }
+
+    private void checkConnected() throws IOException {
+        if (!connected.get()) {
+            throw new IOException("Cannot send to a non-connected transport.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SslTransport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SslTransport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SslTransport.java
new file mode 100644
index 0000000..49d250c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/SslTransport.java
@@ -0,0 +1,59 @@
+/**
+ * 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.jms.transports;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.qpid.jms.JmsSslContext;
+import org.vertx.java.core.net.NetClient;
+
+/**
+ * Provides SSL configuration to the Vert.x NetClient object used by the underling
+ * TCP based Transport.
+ */
+public class SslTransport extends TcpTransport {
+
+    private final JmsSslContext context;
+
+    /**
+     * Create an instance of the SSL transport
+     *
+     * @param listener
+     *        The TransportListener that will handle events from this Transport instance.
+     * @param remoteLocation
+     *        The location that is being connected to.
+     * @param JmsSslContext
+     *        The JMS Framework SslContext to use for this SSL connection.
+     */
+    public SslTransport(TransportListener listener, URI remoteLocation, JmsSslContext context) {
+        super(listener, remoteLocation);
+
+        this.context = context;
+    }
+
+    @Override
+    protected void configureNetClient(NetClient client) throws IOException {
+        super.configureNetClient(client);
+
+        client.setSSL(true);
+        client.setKeyStorePath(context.getKeyStoreLocation());
+        client.setKeyStorePassword(context.getKeyStorePassword());
+        client.setTrustStorePath(context.getTrustStoreLocation());
+        client.setTrustStorePassword(context.getTrustStorePassword());
+    }
+}


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


[13/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MessageIntegrationTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MessageIntegrationTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MessageIntegrationTest.java
new file mode 100644
index 0000000..999df5a
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/MessageIntegrationTest.java
@@ -0,0 +1,957 @@
+/*
+ * 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.jms.integration;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.Date;
+import java.util.UUID;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.apache.qpid.jms.JmsClientProperties;
+import org.apache.qpid.jms.provider.amqp.message.AmqpMessageIdHelper;
+import org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport;
+import org.apache.qpid.jms.test.QpidJmsTestCase;
+import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.AmqpValueDescribedType;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.ApplicationPropertiesDescribedType;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.MessageAnnotationsDescribedType;
+import org.apache.qpid.jms.test.testpeer.describedtypes.sections.PropertiesDescribedType;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.ApplicationPropertiesSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageAnnotationsSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageHeaderSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessagePropertiesSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.TransferPayloadCompositeMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedAmqpValueMatcher;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class MessageIntegrationTest extends QpidJmsTestCase
+{
+    private static final String NULL_STRING_PROP = "nullStringProperty";
+    private static final String NULL_STRING_PROP_VALUE = null;
+    private static final String STRING_PROP = "stringProperty";
+    private static final String STRING_PROP_VALUE = "string";
+    private static final String BOOLEAN_PROP = "booleanProperty";
+    private static final boolean BOOLEAN_PROP_VALUE = true;
+    private static final String BYTE_PROP = "byteProperty";
+    private static final byte   BYTE_PROP_VALUE = (byte)1;
+    private static final String SHORT_PROP = "shortProperty";
+    private static final short  SHORT_PROP_VALUE = (short)1;
+    private static final String INT_PROP = "intProperty";
+    private static final int    INT_PROP_VALUE = Integer.MAX_VALUE;
+    private static final String LONG_PROP = "longProperty";
+    private static final long   LONG_PROP_VALUE = Long.MAX_VALUE;
+    private static final String FLOAT_PROP = "floatProperty";
+    private static final float  FLOAT_PROP_VALUE = Float.MAX_VALUE;
+    private static final String DOUBLE_PROP = "doubleProperty";
+    private static final double DOUBLE_PROP_VALUE = Double.MAX_VALUE;
+
+    private final IntegrationTestFixture _testFixture = new IntegrationTestFixture();
+
+    //TODO: use Message instead of TextMessage
+    @Test(timeout = 2000)
+    public void testSendTextMessageWithApplicationProperties() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            ApplicationPropertiesSectionMatcher appPropsMatcher = new ApplicationPropertiesSectionMatcher(true);
+            appPropsMatcher.withEntry(NULL_STRING_PROP, nullValue());
+            appPropsMatcher.withEntry(STRING_PROP, equalTo(STRING_PROP_VALUE));
+            appPropsMatcher.withEntry(BOOLEAN_PROP, equalTo(BOOLEAN_PROP_VALUE));
+            appPropsMatcher.withEntry(BYTE_PROP, equalTo(BYTE_PROP_VALUE));
+            appPropsMatcher.withEntry(SHORT_PROP, equalTo(SHORT_PROP_VALUE));
+            appPropsMatcher.withEntry(INT_PROP, equalTo(INT_PROP_VALUE));
+            appPropsMatcher.withEntry(LONG_PROP, equalTo(LONG_PROP_VALUE));
+            appPropsMatcher.withEntry(FLOAT_PROP, equalTo(FLOAT_PROP_VALUE));
+            appPropsMatcher.withEntry(DOUBLE_PROP, equalTo(DOUBLE_PROP_VALUE));
+
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true).withDurable(equalTo(true));
+
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true).withTo(equalTo(queueName));
+
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setApplicationPropertiesMatcher(appPropsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(null));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+            message.setStringProperty(NULL_STRING_PROP, NULL_STRING_PROP_VALUE);
+            message.setStringProperty(STRING_PROP, STRING_PROP_VALUE);
+            message.setBooleanProperty(BOOLEAN_PROP, BOOLEAN_PROP_VALUE);
+            message.setByteProperty(BYTE_PROP, BYTE_PROP_VALUE);
+            message.setShortProperty(SHORT_PROP, SHORT_PROP_VALUE);
+            message.setIntProperty(INT_PROP, INT_PROP_VALUE);
+            message.setLongProperty(LONG_PROP, LONG_PROP_VALUE);
+            message.setFloatProperty(FLOAT_PROP, FLOAT_PROP_VALUE);
+            message.setDoubleProperty(DOUBLE_PROP, DOUBLE_PROP_VALUE);
+
+            producer.send(message);
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    @Test(timeout = 2000)
+    public void testReceiveMessageWithApplicationProperties() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setMessageId("myMessageIDString");
+
+            ApplicationPropertiesDescribedType appProperties = new ApplicationPropertiesDescribedType();
+            appProperties.setApplicationProperty(STRING_PROP, STRING_PROP_VALUE);
+            appProperties.setApplicationProperty(NULL_STRING_PROP, NULL_STRING_PROP_VALUE);
+            appProperties.setApplicationProperty(BOOLEAN_PROP, BOOLEAN_PROP_VALUE);
+            appProperties.setApplicationProperty(BYTE_PROP, BYTE_PROP_VALUE);
+            appProperties.setApplicationProperty(SHORT_PROP, SHORT_PROP_VALUE);
+            appProperties.setApplicationProperty(INT_PROP, INT_PROP_VALUE);
+            appProperties.setApplicationProperty(LONG_PROP, LONG_PROP_VALUE);
+            appProperties.setApplicationProperty(FLOAT_PROP, FLOAT_PROP_VALUE);
+            appProperties.setApplicationProperty(DOUBLE_PROP, DOUBLE_PROP_VALUE);
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, appProperties, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertTrue(receivedMessage.propertyExists(STRING_PROP));
+            assertTrue(receivedMessage.propertyExists(NULL_STRING_PROP));
+            assertTrue(receivedMessage.propertyExists(BYTE_PROP));
+            assertTrue(receivedMessage.propertyExists(BOOLEAN_PROP));
+            assertTrue(receivedMessage.propertyExists(SHORT_PROP));
+            assertTrue(receivedMessage.propertyExists(INT_PROP));
+            assertTrue(receivedMessage.propertyExists(LONG_PROP));
+            assertTrue(receivedMessage.propertyExists(FLOAT_PROP));
+            assertTrue(receivedMessage.propertyExists(DOUBLE_PROP));
+            assertNull(receivedMessage.getStringProperty(NULL_STRING_PROP));
+            assertEquals(STRING_PROP_VALUE, receivedMessage.getStringProperty(STRING_PROP));
+            assertEquals(STRING_PROP_VALUE, receivedMessage.getStringProperty(STRING_PROP));
+            assertEquals(BOOLEAN_PROP_VALUE, receivedMessage.getBooleanProperty(BOOLEAN_PROP));
+            assertEquals(BYTE_PROP_VALUE, receivedMessage.getByteProperty(BYTE_PROP));
+            assertEquals(SHORT_PROP_VALUE, receivedMessage.getShortProperty(SHORT_PROP));
+            assertEquals(INT_PROP_VALUE, receivedMessage.getIntProperty(INT_PROP));
+            assertEquals(LONG_PROP_VALUE, receivedMessage.getLongProperty(LONG_PROP));
+            assertEquals(FLOAT_PROP_VALUE, receivedMessage.getFloatProperty(FLOAT_PROP), 0.0);
+            assertEquals(DOUBLE_PROP_VALUE, receivedMessage.getDoubleProperty(DOUBLE_PROP), 0.0);
+        }
+    }
+
+    @Ignore//TODO: currently fails due to NPE during delivery processing due to lack of message id
+    @Test(timeout = 2000)
+    public void testReceiveMessageWithoutMessageId() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, null, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(2000);
+
+            assertNull(receivedMessage.getJMSMessageID());
+        }
+    }
+
+    /**
+     * Tests that the {@link AmqpMessageSupport#AMQP_TO_ANNOTATION} set on a message to
+     * indicate its 'to' address represents a Topic results in the JMSDestination object being a
+     * Topic. Ensure the consumers destination is not used by consuming from a Queue.
+     */
+    @Ignore//TODO: currently fails due to handling of AmqpMessageSupport.AMQP_TO_ANNOTATION not being complete
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithToTypeAnnotationForTopic() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            MessageAnnotationsDescribedType msgAnnotations = new MessageAnnotationsDescribedType();
+            msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.AMQP_TO_ANNOTATION, AmqpMessageSupport.TOPIC_ATTRIBUTES);
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            String myTopicAddress = "myTopicAddress";
+            props.setTo(myTopicAddress );
+            props.setMessageId("myMessageIDString");
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+
+            Destination dest = receivedMessage.getJMSDestination();
+            assertTrue(dest instanceof Topic);
+            assertEquals(myTopicAddress, ((Topic)dest).getTopicName());
+        }
+    }
+
+    /**
+     * Tests that the lack of a 'to' in the Properties section of the incoming message (e.g
+     * one sent by a non-JMS client) is handled by making the JMSDestination method simply
+     * return the Destination used to create the consumer that received the message.
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithoutToResultsInUseOfConsumerDestination() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setMessageId("myMessageIDString");
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+
+            Destination dest = receivedMessage.getJMSDestination();
+            assertTrue(dest instanceof Queue);
+            assertEquals(queueName, ((Queue)dest).getQueueName());
+        }
+    }
+
+    /**
+     * Tests that the {@link AmqpMessageSupport#AMQP_REPLY_TO_ANNOTATION} set on a message to
+     * indicate its 'reply-to' address represents a Topic results in the JMSReplyTo object being a
+     * Topic. Ensure the consumers destination is not used by consuming from a Queue.
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithReplyToTypeAnnotationForTopic() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            MessageAnnotationsDescribedType msgAnnotations = new MessageAnnotationsDescribedType();
+            msgAnnotations.setSymbolKeyedAnnotation(AmqpMessageSupport.AMQP_REPLY_TO_ANNOTATION, AmqpMessageSupport.TOPIC_ATTRIBUTES);
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            String myTopicAddress = "myTopicAddress";
+            props.setReplyTo(myTopicAddress);
+            props.setMessageId("myMessageIDString");
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, msgAnnotations, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+
+            Destination dest = receivedMessage.getJMSReplyTo();
+            assertTrue(dest instanceof Topic);
+            assertEquals(myTopicAddress, ((Topic)dest).getTopicName());
+        }
+    }
+
+    /**
+     * Tests that lack of the {@link AmqpMessageSupport#AMQP_REPLY_TO_ANNOTATION} set on a
+     * message to indicate type of its 'reply-to' address results in it being classed as the same
+     * type as the destination used to create the consumer.
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithReplyToWithoutTypeAnnotationResultsInUseOfConsumerDestinationType() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            String myOtherQueueAddress = "myOtherQueueAddress";
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setReplyTo(myOtherQueueAddress);
+            props.setMessageId("myMessageIDString");
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+
+            Destination dest = receivedMessage.getJMSReplyTo();
+            assertTrue(dest instanceof Queue);
+            assertEquals(myOtherQueueAddress, ((Queue)dest).getQueueName());
+        }
+    }
+
+    /**
+     * Tests that lack of the reply-to set on a message results in it returning null for JMSReplyTo
+     * and not the consumer destination as happens for JMSDestination.
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithNoReplyToReturnsNull() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setMessageId("myMessageIDString");
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+            assertNull(receivedMessage.getJMSReplyTo());
+        }
+    }
+
+    /**
+     * Tests that lack of the absolute-expiry-time and ttl fields on a message results
+     * in it returning 0 for for JMSExpiration
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithNoAbsoluteExpiryOrTtlReturnsJMSExpirationZero() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setMessageId("myMessageIDString");
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+            assertEquals(0L, receivedMessage.getJMSExpiration());
+        }
+    }
+
+    /**
+     * Tests that setting a non-zero value in the absolute-expiry-time field on a
+     * message results in it returning this value for JMSExpiration
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageFromQueueWithAbsoluteExpiryReturnsJMSExpirationNonZero() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            long timestamp = System.currentTimeMillis();
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setAbsoluteExpiryTime(new Date(timestamp));
+            props.setMessageId("myMessageIDString");
+
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+            assertEquals(timestamp, receivedMessage.getJMSExpiration());
+        }
+    }
+
+    /**
+     * Tests that receiving a message with a string typed message-id results in returning the
+     * expected value for JMSMessageId where the JMS "ID:" prefix has been added.
+     */
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithStringMessageIdReturnsExpectedJMSMessageID() throws Exception {
+        receivedMessageWithMessageIdTestImpl("myTestMessageIdString");
+    }
+
+    /**
+     * Tests that receiving a message with a UUID typed message-id results in returning the
+     * expected value for JMSMessageId where the JMS "ID:" prefix has been added to the UUID.tostring()
+     */
+    @Ignore//TODO: failing because handling of non-String messageid values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithUUIDMessageIdReturnsExpectedJMSMessageID() throws Exception {
+        receivedMessageWithMessageIdTestImpl(UUID.randomUUID());
+    }
+
+    /**
+     * Tests that receiving a message with a ulong typed message-id results in returning the
+     * expected value for JMSMessageId where the JMS "ID:" prefix has been added to the UUID.tostring()
+     */
+    @Ignore//TODO: failing because handling of non-String messageid values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithLongMessageIdReturnsExpectedJMSMessageID() throws Exception {
+        receivedMessageWithMessageIdTestImpl(BigInteger.valueOf(123456789L));
+    }
+
+    private void receivedMessageWithMessageIdTestImpl(Object messageIdForAmqpMessageClass) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            Object underlyingAmqpMessageId = classifyUnderlyingIdType(messageIdForAmqpMessageClass);
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setMessageId(underlyingAmqpMessageId);
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+
+            String expectedBaseIdString = new AmqpMessageIdHelper().toBaseMessageIdString(messageIdForAmqpMessageClass);
+
+            assertEquals("ID:" + expectedBaseIdString, receivedMessage.getJMSMessageID());
+        }
+    }
+
+    /**
+     * Tests that receiving a message with a string typed correlation-id results in returning the
+     * expected value for JMSCorrelationID where the JMS "ID:" prefix has been added.
+     */
+    @Test(timeout = 2000)
+    @Ignore//TODO: failing because adding of the 'ID:' prefix to correlation-id values is not yet implemented
+    public void testReceivedMessageWithStringCorrelationIdReturnsExpectedJMSCorrelationID() throws Exception {
+        receivedMessageWithCorrelationIdTestImpl("myTestCorrelationIdString", false);
+    }
+
+    /**
+     * Tests that receiving a message with a string typed correlation-id, which is indicated to be an
+     * application-specific value, results in returning the expected value for JMSCorrelationID
+     * where the JMS "ID:" prefix has NOT been added.
+     */
+    @Ignore//TODO: failing because the transformer code tries to set an illegal JMS property based on the 'x-opt-app-correlation-id' message annotation
+           //TODO: would probably fail anyway because explicit handling based on that annotation is not implemented yet
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithAppSpecificStringCorrelationIdReturnsExpectedJMSCorrelationID() throws Exception {
+        receivedMessageWithCorrelationIdTestImpl("myTestCorrelationIdString", true);
+    }
+
+    /**
+     * Tests that receiving a message with a UUID typed correlation-id results in returning the
+     * expected value for JMSCorrelationID where the JMS "ID:" prefix has been added to the UUID.tostring()
+     */
+    @Ignore//TODO: failing because handling of non-String correlation-id values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithUUIDCorrelationIdReturnsExpectedJMSCorrelationID() throws Exception {
+        receivedMessageWithCorrelationIdTestImpl(UUID.randomUUID(), false);
+    }
+
+    /**
+     * Tests that receiving a message with a UUID typed correlation-id results in returning the
+     * expected value for JMSCorrelationID where the JMS "ID:" prefix has been added to the UUID.tostring()
+     */
+    @Ignore//TODO: failing because handling of non-String correlation-id values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithLongCorrelationIdReturnsExpectedJMSCorrelationID() throws Exception {
+        receivedMessageWithCorrelationIdTestImpl(BigInteger.valueOf(123456789L), false);
+    }
+
+    private void receivedMessageWithCorrelationIdTestImpl(Object correlationIdForAmqpMessageClass, boolean appSpecific) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            Object underlyingAmqpCorrelationId = classifyUnderlyingIdType(correlationIdForAmqpMessageClass);
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+            MessageAnnotationsDescribedType ann = null;
+
+            props.setMessageId("myMessageIdString");
+            props.setCorrelationId(underlyingAmqpCorrelationId);
+            if (appSpecific) {
+                ann = new MessageAnnotationsDescribedType();
+                ann.setSymbolKeyedAnnotation(AmqpMessageSupport.JMS_APP_CORRELATION_ID, true);
+            }
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, ann, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+            String expectedBaseIdString = new AmqpMessageIdHelper().toBaseMessageIdString(correlationIdForAmqpMessageClass);
+            String expected = expectedBaseIdString;
+            if (!appSpecific) {
+                expected = "ID:" + expected;
+            }
+
+            assertEquals(expected, receivedMessage.getJMSCorrelationID());
+        }
+    }
+
+    /**
+     * Tests that sending a message with a uuid typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the type is uuid, the "ID:" prefix of the JMSCorrelationID value is (obviously) not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test(timeout = 2000)
+    @Ignore//TODO: failing because handling of non-String correlation-id values is not yet implemented
+    public void testSentMessageWithUUIDCorrelationId() throws Exception {
+        UUID uuid = UUID.randomUUID();
+        String stringCorrelationId = AmqpMessageIdHelper.JMS_ID_PREFIX + AmqpMessageIdHelper.AMQP_UUID_PREFIX +  uuid.toString();
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, uuid, false);
+    }
+
+    /**
+     * Tests that sending a message with a binary typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the type is binary, the "ID:" prefix of the JMSCorrelationID value is (obviously) not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test(timeout = 2000)
+    @Ignore//TODO: failing because handling of non-String correlation-id values is not yet implemented
+    public void testSentMessageWithBinaryCorrelationId() throws Exception
+    {
+        ByteBuffer bin = ByteBuffer.wrap(new byte[]{(byte)0x01, (byte)0x23, (byte) 0xAF, (byte) 0x00});
+        String stringCorrelationId = AmqpMessageIdHelper.JMS_ID_PREFIX + AmqpMessageIdHelper.AMQP_BINARY_PREFIX +  "0123af00";
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, bin, false);
+    }
+
+    /**
+     * Tests that sending a message with a ulong typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the type is ulong, the "ID:" prefix of the JMSCorrelationID value is (obviously) not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test(timeout = 2000)
+    @Ignore//TODO: failing because handling of non-String correlation-id values is not yet implemented
+    public void testSentMessageWithUlongCorrelationId() throws Exception {
+        BigInteger ulong = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.TEN);
+        String stringCorrelationId = AmqpMessageIdHelper.JMS_ID_PREFIX + AmqpMessageIdHelper.AMQP_ULONG_PREFIX +  ulong.toString();
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, ulong, false);
+    }
+
+    /**
+     * Tests that sending a message with a string typed correlation-id value which is a
+     * message-id results in an AMQP message with the expected encoding of the correlation-id,
+     * where the "ID:" prefix of the JMSCorrelationID value is not present, and there is
+     * no presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Test(timeout = 2000)
+    @Ignore//TODO: failing because removal of the 'ID:' prefix in correlation-id values is not yet implemented
+    public void testSentMessageWithStringCorrelationId() throws Exception {
+        String stringCorrelationId = "ID:myTestMessageIdString";
+        String underlyingCorrelationId = "myTestMessageIdString";
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, underlyingCorrelationId, false);
+    }
+
+    /**
+     * Tests that sending a message with a string typed correlation-id value which is a
+     * app-specific results in an AMQP message with the expected encoding of the correlation-id,
+     * and the presence of the message annotation to indicate an app-specific correlation-id.
+     */
+    @Ignore//TODO: failing because handling of 'x-opt-app-correlation-id' annotation is not yet implemented
+    @Test(timeout = 2000)
+    public void testSentMessageWithAppSpecificStringCorrelationId() throws Exception {
+        String stringCorrelationId = "myTestAppSpecificString";
+        sentMessageWithCorrelationIdTestImpl(stringCorrelationId, stringCorrelationId, true);
+    }
+
+    private void sentMessageWithCorrelationIdTestImpl(String stringCorrelationId, Object correlationIdForAmqpMessageClass, boolean appSpecific) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true);
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true);
+
+            //Set matcher to validate the correlation-id, and the annotation
+            //presence+value if it is application-specific
+            Object underlyingAmqpCorrelationId = classifyUnderlyingIdType(correlationIdForAmqpMessageClass);
+            propsMatcher.withCorrelationId(equalTo(underlyingAmqpCorrelationId));
+            if (appSpecific) {
+                msgAnnotationsMatcher.withEntry(Symbol.valueOf(AmqpMessageSupport.JMS_APP_CORRELATION_ID), equalTo(Boolean.TRUE));
+            }
+
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(null));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+            message.setJMSCorrelationID(stringCorrelationId);
+
+            producer.send(message);
+
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            //validate the annotation was not present if the value was a message-id
+            if (!appSpecific) {
+                assertFalse(msgAnnotationsMatcher.keyExistsInReceivedAnnotations(Symbol.valueOf(AmqpMessageSupport.JMS_APP_CORRELATION_ID)));
+            }
+        }
+    }
+
+    /**
+     * Tests that receiving a message with a string typed message-id, and then sending a message which
+     * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
+     * transmission of the expected AMQP message content.
+     */
+    @Ignore//TODO: failing because removal of the 'ID:' prefix in correlation-id values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithStringMessageIdAndSendValueAsCorrelationId() throws Exception {
+        recieveMessageIdSendCorrelationIdTestImpl("myStringMessageId");
+    }
+
+    /**
+     * Tests that receiving a message with a UUID typed message-id, and then sending a message which
+     * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
+     * transmission of the expected AMQP message content.
+     */
+    @Test(timeout = 2000)
+    @Ignore//TODO: failing because handling of non-String message/correlation-id values is not yet implemented
+    public void testReceivedMessageWithUUIDMessageIdAndSendValueAsCorrelationId() throws Exception {
+        recieveMessageIdSendCorrelationIdTestImpl(UUID.randomUUID());
+    }
+
+    /**
+     * Tests that receiving a message with a ulong typed message-id, and then sending a message which
+     * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
+     * transmission of the expected AMQP message content.
+     */
+    @Ignore//TODO: failing because handling of non-String message/correlation-id values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithUlongMessageIdAndSendValueAsCorrelationId() throws Exception {
+        recieveMessageIdSendCorrelationIdTestImpl(BigInteger.valueOf(123456789L));
+    }
+
+    /**
+     * Tests that receiving a message with a binary typed message-id, and then sending a message which
+     * uses the result of calling getJMSMessageID as the value for setJMSCorrelationId results in
+     * transmission of the expected AMQP message content.
+     */
+    @Ignore//TODO: failing because handling of non-String message/correlation-id values is not yet implemented
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithBinaryMessageIdAndSendValueAsCorrelationId() throws Exception {
+        recieveMessageIdSendCorrelationIdTestImpl(ByteBuffer.wrap(new byte[]{(byte)0x00, (byte)0xCD, (byte) 0xEF, (byte) 0x01}));
+    }
+
+    private void recieveMessageIdSendCorrelationIdTestImpl(Object idForAmqpMessageClass) throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            Object underlyingAmqpMessageId = classifyUnderlyingIdType(idForAmqpMessageClass);
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            props.setMessageId(underlyingAmqpMessageId);
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, null, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull(receivedMessage);
+
+            String expectedBaseIdString = new AmqpMessageIdHelper().toBaseMessageIdString(idForAmqpMessageClass);
+
+            String jmsMessageID = receivedMessage.getJMSMessageID();
+            assertEquals("ID:" + expectedBaseIdString, jmsMessageID);
+
+            //Now take the received JMSMessageID, and send a message with it set
+            //as the JMSCorrelationID and verify we get the same AMQP id as we started with.
+
+            testPeer.expectSenderAttach();
+            MessageProducer producer = session.createProducer(queue);
+
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true);
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true);
+
+            //Set matcher to validate the correlation-id matches the previous message-id
+            propsMatcher.withCorrelationId(equalTo(underlyingAmqpMessageId));
+
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(null));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+            message.setJMSCorrelationID(jmsMessageID);
+
+            producer.send(message);
+
+            testPeer.waitForAllHandlersToComplete(3000);
+        }
+    }
+
+    private Object classifyUnderlyingIdType(Object idForAmqpMessageClass) {
+        Object underlyingAmqpMessageId = idForAmqpMessageClass;
+
+        if (underlyingAmqpMessageId instanceof BigInteger) {
+            // Proton uses UnsignedLong
+            underlyingAmqpMessageId = UnsignedLong.valueOf((BigInteger) underlyingAmqpMessageId);
+        } else if (underlyingAmqpMessageId instanceof ByteBuffer) {
+            // Proton uses Binary
+            underlyingAmqpMessageId = Binary.create((ByteBuffer) underlyingAmqpMessageId);
+        }
+
+        return underlyingAmqpMessageId;
+    }
+
+    /**
+     * Tests that when receiving a message with the group-id, reply-to-group-id, and group-sequence
+     * fields of the AMQP properties section set, that the expected values are returned when getting
+     * the appropriate JMSX or JMS_AMQP properties from the JMS message.
+     */
+    @Ignore//TODO: failing because the JMS_AMQP_REPLY_TO_GROUP_ID property handling is not yet wired up.
+    @Test(timeout = 2000)
+    public void testReceivedMessageWithGroupRelatedPropertiesSet() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            connection.start();
+
+            testPeer.expectBegin(true);
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+
+            PropertiesDescribedType props = new PropertiesDescribedType();
+            DescribedType amqpValueNullContent = new AmqpValueDescribedType(null);
+            MessageAnnotationsDescribedType ann = null;
+
+            String expectedGroupId = "myGroupId123";
+            int expectedGroupSeq = 1;
+            String expectedReplyToGroupId = "myReplyToGroupId456";
+
+            props.setGroupId(expectedGroupId);
+            props.setGroupSequence(UnsignedInteger.valueOf(expectedGroupSeq));
+            props.setReplyToGroupId(expectedReplyToGroupId);
+            props.setMessageId("myMessageIDString");
+
+            testPeer.expectReceiverAttach();
+            testPeer.expectLinkFlowRespondWithTransfer(null, ann, props, null, amqpValueNullContent);
+            testPeer.expectDispositionThatIsAcceptedAndSettled();
+
+            MessageConsumer messageConsumer = session.createConsumer(queue);
+            Message receivedMessage = messageConsumer.receive(1000);
+            testPeer.waitForAllHandlersToComplete(3000);
+
+            assertNotNull("did not receive the message", receivedMessage);
+            assertEquals("did not get the expected JMSXGroupID", expectedGroupId, receivedMessage.getStringProperty(JmsClientProperties.JMSXGROUPID));
+            assertEquals("did not get the expected JMSXGroupSeq", expectedGroupSeq, receivedMessage.getIntProperty(JmsClientProperties.JMSXGROUPSEQ));
+            assertEquals("did not get the expected JMS_AMQP_REPLY_TO_GROUP_ID", expectedReplyToGroupId, receivedMessage.getStringProperty(AmqpMessageSupport.JMS_AMQP_REPLY_TO_GROUP_ID));
+        }
+    }
+
+    /**
+     * Tests that when sending a message with the JMSXGroupID, JMSXGroupSeq, and JMS_AMQP_REPLY_TO_GROUP_ID
+     * properties of the JMS message set, that the expected values are included in the fields of
+     * the AMQP message emitted.
+     */
+    @Ignore//TODO: failing because the JMSXGROUPID etc property handling is not yet wired up.
+    @Test(timeout = 2000)
+    public void testSendMessageWithGroupRelatedPropertiesSet() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = _testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true).withDurable(equalTo(true));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+
+            String expectedGroupId = "myGroupId123";
+            int expectedGroupSeq = 1;
+            String expectedReplyToGroupId = "myReplyToGroupId456";
+
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true);
+            propsMatcher.withGroupId(equalTo(expectedGroupId));
+            propsMatcher.withReplyToGroupId(equalTo(expectedReplyToGroupId));
+            propsMatcher.withGroupSequence(equalTo(UnsignedInteger.valueOf(expectedGroupSeq)));
+
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(null));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+            message.setStringProperty(JmsClientProperties.JMSXGROUPID, expectedGroupId);
+            message.setIntProperty(JmsClientProperties.JMSXGROUPSEQ, expectedGroupSeq);
+            message.setStringProperty(AmqpMessageSupport.JMS_AMQP_REPLY_TO_GROUP_ID, expectedReplyToGroupId);
+
+            producer.send(message);
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SenderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SenderIntegrationTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SenderIntegrationTest.java
new file mode 100644
index 0000000..ac82705
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/SenderIntegrationTest.java
@@ -0,0 +1,379 @@
+/*
+ * 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.jms.integration;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.isA;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport;
+import org.apache.qpid.jms.test.QpidJmsTestCase;
+import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageAnnotationsSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageHeaderSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessagePropertiesSectionMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.TransferPayloadCompositeMatcher;
+import org.apache.qpid.jms.test.testpeer.matchers.types.EncodedAmqpValueMatcher;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class SenderIntegrationTest extends QpidJmsTestCase {
+    private final IntegrationTestFixture testFixture = new IntegrationTestFixture();
+
+    @Test(timeout = 10000)
+    public void testCloseSender() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+            MessageProducer producer = session.createProducer(queue);
+
+            testPeer.expectDetach(true);
+            producer.close();
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    @Test(timeout = 10000)
+    public void testDefaultDeliveryModeProducesDurableMessages() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+            MessageProducer producer = session.createProducer(queue);
+
+            // Create and transfer a new message
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true)
+                    .withDurable(equalTo(true));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+
+            producer.send(message);
+            assertEquals(DeliveryMode.PERSISTENT, message.getJMSDeliveryMode());
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    @Test(timeout = 10000)
+    public void testProducerOverridesMessageDeliveryMode() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+            MessageProducer producer = session.createProducer(queue);
+
+            // Create and transfer a new message, explicitly setting the deliveryMode on the
+            // message (which applications shouldn't) to NON_PERSISTENT and sending it to check
+            // that the producer ignores this value and sends the message as PERSISTENT(/durable)
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true)
+                    .withDurable(equalTo(true));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+            message.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
+            assertEquals(DeliveryMode.NON_PERSISTENT, message.getJMSDeliveryMode());
+
+            producer.send(message);
+
+            assertEquals(DeliveryMode.PERSISTENT, message.getJMSDeliveryMode());
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    /**
+     * Test that when a message is sent the JMSDestination header is set to the Destination used by the
+     * producer, and the emitted AMQP message has the relevant value set in the 'to' field of properties,
+     * with associated message annotation value to indicate the Destination type.
+     */
+    @Test(timeout = 10000)
+    public void testSendingMessageSetsJMSDestination() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            String text = "myMessage";
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true)
+                    .withDurable(equalTo(true));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true)
+                    .withEntry(Symbol.valueOf(AmqpMessageSupport.AMQP_TO_ANNOTATION),
+                            equalTo(AmqpMessageSupport.QUEUE_ATTRIBUTES));
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true)
+                    .withTo(equalTo(queueName));
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(text));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage(text);
+
+            assertNull("Should not yet have a JMSDestination", message.getJMSDestination());
+
+            producer.send(message);
+
+            assertEquals("Should have had JMSDestination set", queue, message.getJMSDestination());
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    @Test(timeout = 10000)
+    public void testSendingMessageSetsJMSTimestamp() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            // Add matcher to expect the creation time field of the properties section to be set to a value greater than
+            // or equal to 'now'
+            Date currentTime = Calendar.getInstance().getTime();
+            String text = "myMessage";
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true)
+                    .withDurable(equalTo(true));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true)
+                    .withCreationTime(greaterThanOrEqualTo(currentTime));
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(text));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage(text);
+
+            producer.send(message);
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    @Ignore
+    // TODO: currently failing as we arent setting the ttl field of header until later in the JMS converter layer, so the value doesnt match expectation
+    @Test(timeout = 10000)
+    public void testSendingMessageSetsJMSExpirationRelatedAbsoluteExpiryAndTtlFields() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            long currentTime = System.currentTimeMillis();
+            long ttl = 100_000;
+            Date expiration = new Date(currentTime + ttl);
+
+            String text = "myMessage";
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true);
+            headersMatcher.withDurable(equalTo(true));
+            headersMatcher.withTtl(equalTo(UnsignedInteger.valueOf(ttl)));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true)
+                    .withAbsoluteExpiryTime(greaterThanOrEqualTo(expiration));
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(text));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage(text);
+
+            producer.send(message, Message.DEFAULT_DELIVERY_MODE, Message.DEFAULT_PRIORITY, ttl);
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    /**
+     * Test that when a message is sent with default priority of 4, the emitted AMQP message has no value in the header
+     * priority field, since the default for that field is already 4.
+     */
+    @Ignore
+    // TODO: currently failing as we always populate the field
+    @Test(timeout = 10000)
+    public void testDefaultPriorityProducesMessagesWithoutPriorityField() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+            MessageProducer producer = session.createProducer(queue);
+
+            // Create and transfer a new message
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true)
+                    .withPriority(equalTo(null));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+
+            assertEquals(Message.DEFAULT_PRIORITY, message.getJMSPriority());
+
+            producer.send(message);
+
+            assertEquals(Message.DEFAULT_PRIORITY, message.getJMSPriority());
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    /**
+     * Test that when a message is sent with a non-default priority, the emitted AMQP message has that value in the
+     * header priority field, and the JMS message has had JMSPriority set.
+     */
+    @Test(timeout = 10000)
+    public void testNonDefaultPriorityProducesMessagesWithPriorityFieldAndSetsJMSPriority() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue("myQueue");
+            MessageProducer producer = session.createProducer(queue);
+
+            byte priority = 5;
+
+            // Create and transfer a new message
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true)
+                    .withPriority(equalTo(UnsignedByte.valueOf(priority)));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage();
+
+            assertEquals(Message.DEFAULT_PRIORITY, message.getJMSPriority());
+
+            producer.send(message, DeliveryMode.PERSISTENT, priority, Message.DEFAULT_TIME_TO_LIVE);
+
+            assertEquals(priority, message.getJMSPriority());
+
+            testPeer.waitForAllHandlersToComplete(1000);
+        }
+    }
+
+    /**
+     * Test that upon sending a message, the sender sets the JMSMessageID on the Message object,
+     * and that the value is included in the AMQP message sent by the client.
+     */
+    @Test(timeout = 10000)
+    public void testSendingMessageSetsJMSMessageID() throws Exception {
+        try(TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            testPeer.expectSenderAttach();
+
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            String queueName = "myQueue";
+            Queue queue = session.createQueue(queueName);
+            MessageProducer producer = session.createProducer(queue);
+
+            String text = "myMessage";
+            MessageHeaderSectionMatcher headersMatcher = new MessageHeaderSectionMatcher(true).withDurable(equalTo(true));
+            MessageAnnotationsSectionMatcher msgAnnotationsMatcher = new MessageAnnotationsSectionMatcher(true);
+            MessagePropertiesSectionMatcher propsMatcher = new MessagePropertiesSectionMatcher(true).withMessageId(isA(String.class));
+            TransferPayloadCompositeMatcher messageMatcher = new TransferPayloadCompositeMatcher();
+            messageMatcher.setHeadersMatcher(headersMatcher);
+            messageMatcher.setMessageAnnotationsMatcher(msgAnnotationsMatcher);
+            messageMatcher.setPropertiesMatcher(propsMatcher);
+            messageMatcher.setMessageContentMatcher(new EncodedAmqpValueMatcher(text));
+            testPeer.expectTransfer(messageMatcher);
+
+            Message message = session.createTextMessage(text);
+
+            assertNull("JMSMessageID should not yet be set", message.getJMSMessageID());
+
+            producer.send(message);
+
+            String jmsMessageID = message.getJMSMessageID();
+            assertNotNull("JMSMessageID should be set", jmsMessageID);
+            assertTrue("JMS 'ID:' prefix not found", jmsMessageID.startsWith("ID:"));
+
+            //Get the value that was actually transmitted/received, verify it is a string, compare to what we have locally
+            testPeer.waitForAllHandlersToComplete(1000);
+            Object receivedMessageId = propsMatcher.getReceivedMessageId();
+
+            assertTrue("Expected string message id to be sent", receivedMessageId instanceof String);
+            assertTrue("Expected JMSMessageId value to be present in AMQP message", jmsMessageID.endsWith((String)receivedMessageId));
+        }
+    }
+}


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


[06/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java
new file mode 100644
index 0000000..eed6826
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageHeaderSectionMatcher.java
@@ -0,0 +1,118 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageListSectionMatcher;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-message-section-matchers.xsl, which resides in this package.
+ */
+public class MessageHeaderSectionMatcher extends MessageListSectionMatcher
+{
+
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:header:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000070L);
+
+    /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+    public enum Field
+    {
+        DURABLE,
+        PRIORITY,
+        TTL,
+        FIRST_ACQUIRER,
+        DELIVERY_COUNT,
+    }
+
+    public MessageHeaderSectionMatcher(boolean expectTrailingBytes)
+    {
+        super(DESCRIPTOR_CODE,
+              DESCRIPTOR_SYMBOL,
+              new HashMap<Object, Matcher<?>>(),
+              expectTrailingBytes);
+    }
+
+
+    public MessageHeaderSectionMatcher withDurable(Matcher<?> m)
+    {
+        getMatchers().put(Field.DURABLE, m);
+        return this;
+    }
+
+    public MessageHeaderSectionMatcher withPriority(Matcher<?> m)
+    {
+        getMatchers().put(Field.PRIORITY, m);
+        return this;
+    }
+
+    public MessageHeaderSectionMatcher withTtl(Matcher<?> m)
+    {
+        getMatchers().put(Field.TTL, m);
+        return this;
+    }
+
+    public MessageHeaderSectionMatcher withFirstAcquirer(Matcher<?> m)
+    {
+        getMatchers().put(Field.FIRST_ACQUIRER, m);
+        return this;
+    }
+
+    public MessageHeaderSectionMatcher withDeliveryCount(Matcher<?> m)
+    {
+        getMatchers().put(Field.DELIVERY_COUNT, m);
+        return this;
+    }
+
+    public Object getReceivedDurable()
+    {
+        return getReceivedFields().get(Field.DURABLE);
+    }
+
+    public Object getReceivedPriority()
+    {
+        return getReceivedFields().get(Field.PRIORITY);
+    }
+
+    public Object getReceivedTtl()
+    {
+        return getReceivedFields().get(Field.TTL);
+    }
+
+    public Object getReceivedFirstAcquirer()
+    {
+        return getReceivedFields().get(Field.FIRST_ACQUIRER);
+    }
+
+    public Object getReceivedDeliveryCount()
+    {
+        return getReceivedFields().get(Field.DELIVERY_COUNT);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java
new file mode 100644
index 0000000..01d8ab0
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageListSectionMatcher.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public abstract class MessageListSectionMatcher extends AbstractMessageSectionMatcher
+{
+    public MessageListSectionMatcher(UnsignedLong numericDescriptor,
+                                            Symbol symbolicDescriptor,
+                                            Map<Object, Matcher<?>> fieldMatchers,
+                                            boolean expectTrailingBytes)
+    {
+        super(numericDescriptor, symbolicDescriptor, fieldMatchers, expectTrailingBytes);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected void verifyReceivedDescribedObject(Object described)
+    {
+        if(!(described instanceof List))
+        {
+            throw new IllegalArgumentException("Unexpected section contents. Expected List, but got: "
+                                              + (described == null ? "null" : described.getClass()));
+        }
+
+        int fieldNumber = 0;
+        Map<Object, Object> valueMap = new HashMap<Object, Object>();
+        for(Object value : (List<Object>)described)
+        {
+            valueMap.put(getField(fieldNumber++), value);
+        }
+
+        verifyReceivedFields(valueMap);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java
new file mode 100644
index 0000000..be3f0a4
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessageMapSectionMatcher.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+
+public abstract class MessageMapSectionMatcher extends AbstractMessageSectionMatcher
+{
+    public MessageMapSectionMatcher(UnsignedLong numericDescriptor,
+                                            Symbol symbolicDescriptor,
+                                            Map<Object, Matcher<?>> fieldMatchers,
+                                            boolean expectTrailingBytes)
+    {
+        super(numericDescriptor, symbolicDescriptor, fieldMatchers, expectTrailingBytes);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    protected void verifyReceivedDescribedObject(Object described)
+    {
+        if(!(described instanceof Map))
+        {
+            throw new IllegalArgumentException("Unexpected section contents. Expected Map, but got: "
+                                              + (described == null ? "null" : described.getClass()));
+        }
+
+        verifyReceivedFields((Map<Object,Object>) described);
+    }
+
+    public MessageMapSectionMatcher withEntry(Object key, Matcher<?> m)
+    {
+        getMatchers().put(key, m);
+        return this;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java
new file mode 100644
index 0000000..35a523a
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/MessagePropertiesSectionMatcher.java
@@ -0,0 +1,214 @@
+/*
+ * 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.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.MessageListSectionMatcher;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-message-section-matchers.xsl, which resides in this package.
+ */
+public class MessagePropertiesSectionMatcher extends MessageListSectionMatcher
+{
+
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:properties:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000073L);
+
+    /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+    public enum Field
+    {
+        MESSAGE_ID,
+        USER_ID,
+        TO,
+        SUBJECT,
+        REPLY_TO,
+        CORRELATION_ID,
+        CONTENT_TYPE,
+        CONTENT_ENCODING,
+        ABSOLUTE_EXPIRY_TIME,
+        CREATION_TIME,
+        GROUP_ID,
+        GROUP_SEQUENCE,
+        REPLY_TO_GROUP_ID,
+    }
+
+    public MessagePropertiesSectionMatcher(boolean expectTrailingBytes)
+    {
+        super(DESCRIPTOR_CODE,
+              DESCRIPTOR_SYMBOL,
+              new HashMap<Object, Matcher<?>>(),
+              expectTrailingBytes);
+    }
+
+
+    public MessagePropertiesSectionMatcher withMessageId(Matcher<?> m)
+    {
+        getMatchers().put(Field.MESSAGE_ID, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withUserId(Matcher<?> m)
+    {
+        getMatchers().put(Field.USER_ID, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withTo(Matcher<?> m)
+    {
+        getMatchers().put(Field.TO, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withSubject(Matcher<?> m)
+    {
+        getMatchers().put(Field.SUBJECT, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withReplyTo(Matcher<?> m)
+    {
+        getMatchers().put(Field.REPLY_TO, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withCorrelationId(Matcher<?> m)
+    {
+        getMatchers().put(Field.CORRELATION_ID, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withContentType(Matcher<?> m)
+    {
+        getMatchers().put(Field.CONTENT_TYPE, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withContentEncoding(Matcher<?> m)
+    {
+        getMatchers().put(Field.CONTENT_ENCODING, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withAbsoluteExpiryTime(Matcher<?> m)
+    {
+        getMatchers().put(Field.ABSOLUTE_EXPIRY_TIME, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withCreationTime(Matcher<?> m)
+    {
+        getMatchers().put(Field.CREATION_TIME, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withGroupId(Matcher<?> m)
+    {
+        getMatchers().put(Field.GROUP_ID, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withGroupSequence(Matcher<?> m)
+    {
+        getMatchers().put(Field.GROUP_SEQUENCE, m);
+        return this;
+    }
+
+    public MessagePropertiesSectionMatcher withReplyToGroupId(Matcher<?> m)
+    {
+        getMatchers().put(Field.REPLY_TO_GROUP_ID, m);
+        return this;
+    }
+
+    public Object getReceivedMessageId()
+    {
+        return getReceivedFields().get(Field.MESSAGE_ID);
+    }
+
+    public Object getReceivedUserId()
+    {
+        return getReceivedFields().get(Field.USER_ID);
+    }
+
+    public Object getReceivedTo()
+    {
+        return getReceivedFields().get(Field.TO);
+    }
+
+    public Object getReceivedSubject()
+    {
+        return getReceivedFields().get(Field.SUBJECT);
+    }
+
+    public Object getReceivedReplyTo()
+    {
+        return getReceivedFields().get(Field.REPLY_TO);
+    }
+
+    public Object getReceivedCorrelationId()
+    {
+        return getReceivedFields().get(Field.CORRELATION_ID);
+    }
+
+    public Object getReceivedContentType()
+    {
+        return getReceivedFields().get(Field.CONTENT_TYPE);
+    }
+
+    public Object getReceivedContentEncoding()
+    {
+        return getReceivedFields().get(Field.CONTENT_ENCODING);
+    }
+
+    public Object getReceivedAbsoluteExpiryTime()
+    {
+        return getReceivedFields().get(Field.ABSOLUTE_EXPIRY_TIME);
+    }
+
+    public Object getReceivedCreationTime()
+    {
+        return getReceivedFields().get(Field.CREATION_TIME);
+    }
+
+    public Object getReceivedGroupId()
+    {
+        return getReceivedFields().get(Field.GROUP_ID);
+    }
+
+    public Object getReceivedGroupSequence()
+    {
+        return getReceivedFields().get(Field.GROUP_SEQUENCE);
+    }
+
+    public Object getReceivedReplyToGroupId()
+    {
+        return getReceivedFields().get(Field.REPLY_TO_GROUP_ID);
+    }
+
+    @Override
+    protected Enum<?> getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java
new file mode 100644
index 0000000..a49b8a4
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/TransferPayloadCompositeMatcher.java
@@ -0,0 +1,224 @@
+/*
+ *
+ * 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.jms.test.testpeer.matchers.sections;
+
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.StringDescription;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * Used to verify the Transfer frame payload, i.e the sections of the AMQP message
+ * such as the header, properties, and body sections.
+ */
+public class TransferPayloadCompositeMatcher extends TypeSafeMatcher<Binary>
+{
+    private MessageHeaderSectionMatcher _msgHeadersMatcher;
+    private String _msgHeaderMatcherFailureDescription;
+
+    private MessageAnnotationsSectionMatcher _msgAnnotationsMatcher;
+    private String _msgAnnotationsMatcherFailureDescription;
+    private MessagePropertiesSectionMatcher _propsMatcher;
+    private String _propsMatcherFailureDescription;
+    private Matcher<Binary> _msgContentMatcher;
+    private String _msgContentMatcherFailureDescription;
+    private ApplicationPropertiesSectionMatcher _appPropsMatcher;
+    private String _appPropsMatcherFailureDescription;
+
+    public TransferPayloadCompositeMatcher()
+    {
+    }
+
+    @Override
+    protected boolean matchesSafely(final Binary receivedBinary)
+    {
+        int origLength = receivedBinary.getLength();
+        int bytesConsumed = 0;
+
+        //MessageHeader Section
+        if(_msgHeadersMatcher != null)
+        {
+            Binary msgHeaderEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+            try
+            {
+                bytesConsumed += _msgHeadersMatcher.verify(msgHeaderEtcSubBinary);
+            }
+            catch(Throwable t)
+            {
+                _msgHeaderMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to MessageHeaderMatcher: " + msgHeaderEtcSubBinary;
+                _msgHeaderMatcherFailureDescription += "\nMessageHeaderMatcher generated throwable: " + t;
+
+                return false;
+            }
+        }
+
+        //MessageAnnotations Section
+        if(_msgAnnotationsMatcher != null)
+        {
+            Binary msgAnnotationsEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+            try
+            {
+                bytesConsumed += _msgAnnotationsMatcher.verify(msgAnnotationsEtcSubBinary);
+            }
+            catch(Throwable t)
+            {
+                _msgAnnotationsMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to MessageAnnotationsMatcher: " + msgAnnotationsEtcSubBinary;
+                _msgAnnotationsMatcherFailureDescription += "\nMessageAnnotationsMatcher generated throwable: " + t;
+
+                return false;
+            }
+        }
+
+        //Properties Section
+        if(_propsMatcher != null)
+        {
+            Binary propsEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+            try
+            {
+                bytesConsumed += _propsMatcher.verify(propsEtcSubBinary);
+            }
+            catch(Throwable t)
+            {
+                _propsMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to PropertiesMatcher: " + propsEtcSubBinary;
+                _propsMatcherFailureDescription += "\nPropertiesMatcher generated throwable: " + t;
+
+                return false;
+            }
+        }
+
+        //Application Properties Section
+        if(_appPropsMatcher != null)
+        {
+            Binary appPropsEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+            try
+            {
+                bytesConsumed += _appPropsMatcher.verify(appPropsEtcSubBinary);
+            }
+            catch(Throwable t)
+            {
+                _appPropsMatcherFailureDescription = "\nActual encoded form of remaining bytes passed to ApplicationPropertiesMatcher: " + appPropsEtcSubBinary;
+                _appPropsMatcherFailureDescription += "\nApplicationPropertiesMatcher generated throwable: " + t;
+
+                return false;
+            }
+        }
+        //Message Content Body Section, already a Matcher<Binary>
+        if(_msgContentMatcher != null)
+        {
+            Binary msgContentBodyEtcSubBinary = receivedBinary.subBinary(bytesConsumed, origLength - bytesConsumed);
+            boolean contentMatches = _msgContentMatcher.matches(msgContentBodyEtcSubBinary);
+            if(!contentMatches)
+            {
+                Description desc = new StringDescription();
+                _msgContentMatcher.describeTo(desc);
+                _msgContentMatcher.describeMismatch(msgContentBodyEtcSubBinary, desc);
+
+                _msgContentMatcherFailureDescription = "\nMessageContentMatcher mismatch Description:";
+                _msgContentMatcherFailureDescription += desc.toString();
+
+                return false;
+            }
+        }
+
+        //TODO: we will need figure out a way to determine how many bytes the
+        //MessageContentMatcher did/should consume when it comes time to handle footers
+        return true;
+    }
+
+    @Override
+    public void describeTo(Description description)
+    {
+        description.appendText("a Binary encoding of a Transfer frames payload, containing an AMQP message");
+    }
+
+    @Override
+    protected void describeMismatchSafely(Binary item, Description mismatchDescription)
+    {
+        mismatchDescription.appendText("\nActual encoded form of the full Transfer frame payload: ").appendValue(item);
+
+        //MessageHeaders Section
+        if(_msgHeaderMatcherFailureDescription != null)
+        {
+            mismatchDescription.appendText("\nMessageHeadersMatcherFailed!");
+            mismatchDescription.appendText(_msgHeaderMatcherFailureDescription);
+            return;
+        }
+
+        //MessageAnnotations Section
+        if(_msgAnnotationsMatcherFailureDescription != null)
+        {
+            mismatchDescription.appendText("\nMessageAnnotationsMatcherFailed!");
+            mismatchDescription.appendText(_msgAnnotationsMatcherFailureDescription);
+            return;
+        }
+
+        //Properties Section
+        if(_propsMatcherFailureDescription != null)
+        {
+            mismatchDescription.appendText("\nPropertiesMatcherFailed!");
+            mismatchDescription.appendText(_propsMatcherFailureDescription);
+            return;
+        }
+
+        //Application Properties Section
+        if(_appPropsMatcherFailureDescription != null)
+        {
+            mismatchDescription.appendText("\nApplicationPropertiesMatcherFailed!");
+            mismatchDescription.appendText(_appPropsMatcherFailureDescription);
+            return;
+        }
+
+        //Message Content Body Section
+        if(_msgContentMatcherFailureDescription != null)
+        {
+            mismatchDescription.appendText("\nContentMatcherFailed!");
+            mismatchDescription.appendText(_msgContentMatcherFailureDescription);
+            return;
+        }
+    }
+
+    public void setHeadersMatcher(MessageHeaderSectionMatcher msgHeadersMatcher)
+    {
+        _msgHeadersMatcher = msgHeadersMatcher;
+    }
+
+    public void setMessageAnnotationsMatcher(MessageAnnotationsSectionMatcher msgAnnotationsMatcher)
+    {
+        _msgAnnotationsMatcher = msgAnnotationsMatcher;
+    }
+
+    public void setPropertiesMatcher(MessagePropertiesSectionMatcher propsMatcher)
+    {
+        _propsMatcher = propsMatcher;
+    }
+
+    public void setApplicationPropertiesMatcher(ApplicationPropertiesSectionMatcher appPropsMatcher)
+    {
+        _appPropsMatcher = appPropsMatcher;
+    }
+
+    public void setMessageContentMatcher(Matcher<Binary> msgContentMatcher)
+    {
+        _msgContentMatcher = msgContentMatcher;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl
new file mode 100644
index 0000000..22277d3
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/sections/generate-message-section-matchers.xsl
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+                xmlns:exsl="http://exslt.org/common"
+                extension-element-prefixes="exsl">
+
+<!-- Used to generate the Java classes in this package.
+     Changes to these classes should be effected by modifying this stylesheet then re-running it,
+     using a stylesheet processor that understands the exsl directives such as xsltproc -->
+
+<xsl:template match="/">
+    <xsl:variable name="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.
+ *
+ */
+</xsl:variable>
+
+    <xsl:for-each select="descendant-or-self::node()[name()='type']">
+        <xsl:variable name="classname">Message<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>SectionMatcher</xsl:variable>
+        <xsl:variable name="superclass">
+            <xsl:choose>
+                <xsl:when test="@name = 'header' or @name='properties'">MessageListSectionMatcher</xsl:when>
+                <xsl:otherwise>NotYetImplemented</xsl:otherwise>
+            </xsl:choose>
+        </xsl:variable>
+
+        <xsl:if test="@provides = 'section'">
+            <xsl:if test="@name = 'header' or @name='properties'">
+              <xsl:call-template name="typeClass">
+                  <xsl:with-param name="license" select="$license"/>
+                  <xsl:with-param name="classname" select="$classname"/>
+                  <xsl:with-param name="superclass" select="$superclass"/>
+              </xsl:call-template>
+            </xsl:if>
+        </xsl:if>
+
+    </xsl:for-each>
+</xsl:template>
+
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="typeClass">
+    <xsl:param name="license"/>
+    <xsl:param name="classname"/>
+    <xsl:param name="superclass"/>
+  <exsl:document href="{$classname}.java" method="text">
+  <xsl:value-of select="$license"/>
+package org.apache.qpid.jms.test.testpeer.matchers.sections;
+
+import java.util.HashMap;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.jms.test.testpeer.matchers.sections.<xsl:value-of select="$superclass"/>;
+import org.hamcrest.Matcher;
+
+/**
+ * Generated by generate-message-section-matchers.xsl, which resides in this package.
+ */
+public class <xsl:value-of select="$classname"/> extends <xsl:value-of select="$superclass"/>
+{
+
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("<xsl:value-of select="descendant::node()[name()='descriptor']/@name"/>");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(<xsl:value-of select="concat(substring(descendant::node()[name()='descriptor']/@code,1,10),substring(descendant::node()[name()='descriptor']/@code,14))"/>L);
+
+    /** Note that the ordinals of the Field enums match the order specified in the AMQP spec */
+    public enum Field
+    {
+<xsl:for-each select="descendant::node()[name()='field']">
+<xsl:text>        </xsl:text><xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>,
+</xsl:for-each>    }
+
+    public <xsl:value-of select="$classname"/>(boolean expectTrailingBytes)
+    {
+        super(DESCRIPTOR_CODE,
+              DESCRIPTOR_SYMBOL,
+              new HashMap&lt;Object, Matcher&lt;?&gt;&gt;(),
+              expectTrailingBytes);
+    }
+
+<xsl:for-each select="descendant::node()[name()='field']">
+    public <xsl:value-of select="$classname"/> with<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>(Matcher&lt;?&gt; m)
+    {
+        getMatchers().put(Field.<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>, m);
+        return this;
+    }
+</xsl:for-each>
+<xsl:for-each select="descendant::node()[name()='field']">
+    public Object getReceived<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>()
+    {
+        return getReceivedFields().get(Field.<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>);
+    }
+</xsl:for-each>
+    @Override
+    protected Enum&lt;?&gt; getField(int fieldIndex)
+    {
+        return Field.values()[fieldIndex];
+    }
+}
+
+</exsl:document>
+
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="constructFromLiteral">
+    <xsl:param name="type"/>
+    <xsl:param name="value"/>
+    <xsl:choose>
+        <xsl:when test="$type = 'string'">"<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'symbol'">Symbol.valueOf("<xsl:value-of select="$value"/>")</xsl:when>
+        <xsl:when test="$type = 'ubyte'">UnsignedByte.valueOf((byte) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ushort'">UnsignedShort.valueOf((short) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'uint'">UnsignedInteger.valueOf(<xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ulong'">UnsignedLong.valueOf(<xsl:value-of select="$value"/>L)</xsl:when>
+        <xsl:when test="$type = 'long'"><xsl:value-of select="$value"/>L</xsl:when>
+        <xsl:when test="$type = 'short'">(short)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'short'">(byte)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
+    </xsl:choose>
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+<xsl:template name="substringAfterLast"><xsl:param name="input"/><xsl:param name="arg"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,$arg)"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input"><xsl:value-of select="substring-after($input,$arg)"/></xsl:with-param><xsl:with-param name="arg"><xsl:value-of select="$arg"/></xsl:with-param></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$input"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="initCap"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="initLower"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="toUpper"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:template>
+
+    <xsl:template name="toUpperDashToUnderscore"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz-','ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/></xsl:template>
+
+    <xsl:template name="dashToCamel">
+        <xsl:param name="input"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,'-')"><xsl:call-template name="initCap"><xsl:with-param name="input" select="substring-before($input,'-')"/></xsl:call-template><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="substring-after($input,'-')"/></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:call-template name="initCap"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="dashToLowerCamel">
+        <xsl:param name="input"/>
+        <xsl:call-template name="initLower"><xsl:with-param name="input"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:with-param></xsl:call-template>
+    </xsl:template>
+</xsl:stylesheet>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java
new file mode 100644
index 0000000..797ee4a
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpTypeMatcher.java
@@ -0,0 +1,114 @@
+/*
+ * 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.jms.test.testpeer.matchers.types;
+
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.proton.codec.Data;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+public abstract class EncodedAmqpTypeMatcher extends TypeSafeMatcher<Binary>
+{
+    private final Symbol _descriptorSymbol;
+    private final UnsignedLong _descriptorCode;
+    private final Object _expectedValue;
+    private boolean _permitTrailingBytes;
+    private DescribedType _decodedDescribedType;
+    private boolean _unexpectedTrailingBytes;
+
+    public EncodedAmqpTypeMatcher(Symbol symbol, UnsignedLong code, Object expectedValue)
+    {
+        this(symbol, code, expectedValue, false);
+    }
+
+    public EncodedAmqpTypeMatcher(Symbol symbol, UnsignedLong code, Object expectedValue, boolean permitTrailingBytes)
+    {
+        _descriptorSymbol = symbol;
+        _descriptorCode = code;
+        _expectedValue = expectedValue;
+        _permitTrailingBytes = permitTrailingBytes;
+    }
+
+    protected Object getExpectedValue()
+    {
+        return _expectedValue;
+    }
+
+    @Override
+    protected boolean matchesSafely(Binary receivedBinary)
+    {
+        int length = receivedBinary.getLength();
+        Data data = Proton.data(length);
+        long decoded = data.decode(receivedBinary.asByteBuffer());
+        _decodedDescribedType = data.getDescribedType();
+        Object descriptor = _decodedDescribedType.getDescriptor();
+
+        if(!(_descriptorCode.equals(descriptor) || _descriptorSymbol.equals(descriptor)))
+        {
+            return false;
+        }
+
+        if(_expectedValue == null && _decodedDescribedType.getDescribed() != null)
+        {
+            return false;
+        }
+        else if(_expectedValue != null && !_expectedValue.equals(_decodedDescribedType.getDescribed()))
+        {
+            return false;
+        }
+
+        if(decoded < length && !_permitTrailingBytes)
+        {
+            _unexpectedTrailingBytes = true;
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    protected void describeMismatchSafely(Binary item, Description mismatchDescription)
+    {
+        mismatchDescription.appendText("\nActual encoded form: ").appendValue(item);
+
+        if(_decodedDescribedType != null)
+        {
+            mismatchDescription.appendText("\nExpected descriptor: ")
+                .appendValue(_descriptorSymbol)
+                .appendText(" / ")
+                .appendValue(_descriptorCode);
+
+            mismatchDescription.appendText("\nActual described type: ").appendValue(_decodedDescribedType);
+        }
+
+        if(_unexpectedTrailingBytes)
+        {
+            mismatchDescription.appendText("\nUnexpected trailing bytes in provided bytes after decoding!");
+        }
+    }
+
+    /**
+     * Provide a description of this matcher.
+     */
+    public abstract void describeTo(Description description);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java
new file mode 100644
index 0000000..93dcc36
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedAmqpValueMatcher.java
@@ -0,0 +1,56 @@
+/*
+ * 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.jms.test.testpeer.matchers.types;
+
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Description;
+
+public class EncodedAmqpValueMatcher extends EncodedAmqpTypeMatcher
+{
+    private static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:amqp-value:*");
+    private static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000077L);
+
+    /**
+     * @param expectedValue the value that is expected to be IN the
+     * received {@link AmqpValue}
+     */
+    public EncodedAmqpValueMatcher(Object expectedValue)
+    {
+        this(expectedValue,false);
+    }
+
+    /**
+     * @param expectedValue the value that is expected to be IN the
+     * received {@link AmqpValue}
+     * @param permitTrailingBytes if it is permitted for bytes to be left in the Binary after consuming the {@link AmqpValue}
+     */
+    public EncodedAmqpValueMatcher(Object expectedValue, boolean permitTrailingBytes)
+    {
+        super(DESCRIPTOR_SYMBOL, DESCRIPTOR_CODE, expectedValue, permitTrailingBytes);
+    }
+
+    @Override
+    public void describeTo(Description description)
+    {
+        description
+            .appendText("a Binary encoding of an AmqpValue that wraps: ")
+            .appendValue(getExpectedValue());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java
new file mode 100644
index 0000000..94cea5e
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/matchers/types/EncodedDataMatcher.java
@@ -0,0 +1,58 @@
+/*
+ * 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.jms.test.testpeer.matchers.types;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Description;
+
+public class EncodedDataMatcher extends EncodedAmqpTypeMatcher
+{
+    private static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:data:binary");
+    private static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000075L);
+
+    /**
+     * @param expectedValue the value that is expected to be IN the
+     * received {@link org.apache.qpid.proton.amqp.messaging.Data}
+     */
+    public EncodedDataMatcher(Binary expectedValue)
+    {
+        this(expectedValue, false);
+    }
+
+    /**
+     * @param expectedValue the value that is expected to be IN the
+     * received {@link org.apache.qpid.proton.amqp.messaging.Data}
+     * @param permitTrailingBytes if it is permitted for bytes to be left in the Binary after consuming the {@link AmqpValue}
+     */
+    public EncodedDataMatcher(Binary expectedValue, boolean permitTrailingBytes)
+    {
+        super(DESCRIPTOR_SYMBOL, DESCRIPTOR_CODE, expectedValue, permitTrailingBytes);
+    }
+
+    @Override
+    public void describeTo(Description description)
+    {
+        description
+            .appendText("a Binary encoding of a Data that wraps a Binary containing: ")
+            .appendValue(getExpectedValue());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
new file mode 100644
index 0000000..7459e82
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/util/URISupportTest.java
@@ -0,0 +1,216 @@
+/**
+ * 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.jms.util;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+import org.apache.qpid.jms.util.URISupport.CompositeData;
+
+import junit.framework.TestCase;
+
+public class URISupportTest extends TestCase {
+
+    public void testEmptyCompositePath() throws Exception {
+        CompositeData data = URISupport.parseComposite(new URI("broker:()/localhost?persistent=false"));
+        assertEquals(0, data.getComponents().length);
+    }
+
+    public void testCompositePath() throws Exception {
+        CompositeData data = URISupport.parseComposite(new URI("test:(path)/path"));
+        assertEquals("path", data.getPath());
+        data = URISupport.parseComposite(new URI("test:path"));
+        assertNull(data.getPath());
+    }
+
+    public void testSimpleComposite() throws Exception {
+        CompositeData data = URISupport.parseComposite(new URI("test:part1"));
+        assertEquals(1, data.getComponents().length);
+    }
+
+    public void testComposite() throws Exception {
+        URI uri = new URI("test:(part1://host,part2://(sub1://part,sube2:part))");
+        CompositeData data = URISupport.parseComposite(uri);
+        assertEquals(2, data.getComponents().length);
+    }
+
+    public void testEmptyCompositeWithParenthesisInParam() throws Exception {
+        URI uri = new URI("failover://()?updateURIsURL=file:/C:/Dir(1)/a.csv");
+        CompositeData data = URISupport.parseComposite(uri);
+        assertEquals(0, data.getComponents().length);
+        assertEquals(1, data.getParameters().size());
+        assertTrue(data.getParameters().containsKey("updateURIsURL"));
+        assertEquals("file:/C:/Dir(1)/a.csv", data.getParameters().get("updateURIsURL"));
+    }
+
+    public void testCompositeWithParenthesisInParam() throws Exception {
+        URI uri = new URI("failover://(test)?updateURIsURL=file:/C:/Dir(1)/a.csv");
+        CompositeData data = URISupport.parseComposite(uri);
+        assertEquals(1, data.getComponents().length);
+        assertEquals(1, data.getParameters().size());
+        assertTrue(data.getParameters().containsKey("updateURIsURL"));
+        assertEquals("file:/C:/Dir(1)/a.csv", data.getParameters().get("updateURIsURL"));
+    }
+
+    public void testCompositeWithComponentParam() throws Exception {
+        CompositeData data = URISupport.parseComposite(new URI("test:(part1://host?part1=true)?outside=true"));
+        assertEquals(1, data.getComponents().length);
+        assertEquals(1, data.getParameters().size());
+        Map<String, String> part1Params = URISupport.parseParameters(data.getComponents()[0]);
+        assertEquals(1, part1Params.size());
+        assertTrue(part1Params.containsKey("part1"));
+    }
+
+    public void testParsingURI() throws Exception {
+        URI source = new URI("tcp://localhost:61626/foo/bar?cheese=Edam&x=123");
+
+        Map<String, String> map = PropertyUtil.parseParameters(source);
+
+        assertEquals("Size: " + map, 2, map.size());
+        assertMapKey(map, "cheese", "Edam");
+        assertMapKey(map, "x", "123");
+
+        URI result = URISupport.removeQuery(source);
+
+        assertEquals("result", new URI("tcp://localhost:61626/foo/bar"), result);
+    }
+
+    protected void assertMapKey(Map<String, String> map, String key, Object expected) {
+        assertEquals("Map key: " + key, map.get(key), expected);
+    }
+
+    public void testParsingCompositeURI() throws URISyntaxException {
+        CompositeData data = URISupport.parseComposite(new URI("broker://(tcp://localhost:61616)?name=foo"));
+        assertEquals("one component", 1, data.getComponents().length);
+        assertEquals("Size: " + data.getParameters(), 1, data.getParameters().size());
+    }
+
+    public void testCheckParenthesis() throws Exception {
+        String str = "fred:(((ddd))";
+        assertFalse(URISupport.checkParenthesis(str));
+        str += ")";
+        assertTrue(URISupport.checkParenthesis(str));
+    }
+
+    public void testCreateWithQuery() throws Exception {
+        URI source = new URI("vm://localhost");
+        URI dest = PropertyUtil.replaceQuery(source, "network=true&one=two");
+
+        assertEquals("correct param count", 2, URISupport.parseParameters(dest).size());
+        assertEquals("same uri, host", source.getHost(), dest.getHost());
+        assertEquals("same uri, scheme", source.getScheme(), dest.getScheme());
+        assertFalse("same uri, ssp", dest.getQuery().equals(source.getQuery()));
+    }
+
+    public void testParsingParams() throws Exception {
+        URI uri = new URI("static:(http://localhost:61617?proxyHost=jo&proxyPort=90)?proxyHost=localhost&proxyPort=80");
+        Map<String,String>parameters = URISupport.parseParameters(uri);
+        verifyParams(parameters);
+        uri = new URI("static://http://localhost:61617?proxyHost=localhost&proxyPort=80");
+        parameters = URISupport.parseParameters(uri);
+        verifyParams(parameters);
+        uri = new URI("http://0.0.0.0:61616");
+        parameters = URISupport.parseParameters(uri);
+    }
+
+    public void testCompositeCreateURIWithQuery() throws Exception {
+        String queryString = "query=value";
+        URI originalURI = new URI("outerscheme:(innerscheme:innerssp)");
+        URI querylessURI = originalURI;
+        assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+        assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+        assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+        originalURI = new URI("outerscheme:(innerscheme:innerssp)?outerquery=0");
+        assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+        assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+        assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+        originalURI = new URI("outerscheme:(innerscheme:innerssp?innerquery=0)");
+        querylessURI = originalURI;
+        assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+        assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+        assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+        originalURI = new URI("outerscheme:(innerscheme:innerssp?innerquery=0)?outerquery=0");
+        assertEquals(querylessURI, PropertyUtil.eraseQuery(originalURI));
+        assertEquals(querylessURI, PropertyUtil.replaceQuery(originalURI, ""));
+        assertEquals(new URI(querylessURI + "?" + queryString), PropertyUtil.replaceQuery(originalURI, queryString));
+    }
+
+    public void testApplyParameters() throws Exception {
+
+        URI uri = new URI("http://0.0.0.0:61616");
+        Map<String,String> parameters = new HashMap<String, String>();
+        parameters.put("t.proxyHost", "localhost");
+        parameters.put("t.proxyPort", "80");
+
+        uri = URISupport.applyParameters(uri, parameters);
+        Map<String,String> appliedParameters = URISupport.parseParameters(uri);
+        assertEquals("all params applied  with no prefix", 2, appliedParameters.size());
+
+        // strip off params again
+        uri = PropertyUtil.eraseQuery(uri);
+
+        uri = URISupport.applyParameters(uri, parameters, "joe");
+        appliedParameters = URISupport.parseParameters(uri);
+        assertTrue("no params applied as none match joe", appliedParameters.isEmpty());
+
+        uri = URISupport.applyParameters(uri, parameters, "t.");
+        verifyParams(URISupport.parseParameters(uri));
+    }
+
+    private void verifyParams(Map<String,String> parameters) {
+        assertEquals(parameters.get("proxyHost"), "localhost");
+        assertEquals(parameters.get("proxyPort"), "80");
+    }
+
+    public void testIsCompositeURIWithQueryNoSlashes() throws URISyntaxException {
+        URI[] compositeURIs = new URI[] { new URI("test:(part1://host?part1=true)?outside=true"), new URI("broker:(tcp://localhost:61616)?name=foo") };
+        for (URI uri : compositeURIs) {
+            assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+        }
+    }
+
+    public void testIsCompositeURIWithQueryAndSlashes() throws URISyntaxException {
+        URI[] compositeURIs = new URI[] { new URI("test://(part1://host?part1=true)?outside=true"), new URI("broker://(tcp://localhost:61616)?name=foo") };
+        for (URI uri : compositeURIs) {
+            assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+        }
+    }
+
+    public void testIsCompositeURINoQueryNoSlashes() throws URISyntaxException {
+        URI[] compositeURIs = new URI[] { new URI("test:(part1://host,part2://(sub1://part,sube2:part))"), new URI("test:(path)/path") };
+        for (URI uri : compositeURIs) {
+            assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+        }
+    }
+
+    public void testIsCompositeURINoQueryNoSlashesNoParentheses() throws URISyntaxException {
+        assertFalse("test:part1" + " must be detected as non-composite URI", URISupport.isCompositeURI(new URI("test:part1")));
+    }
+
+    public void testIsCompositeURINoQueryWithSlashes() throws URISyntaxException {
+        URI[] compositeURIs = new URI[] { new URI("failover://(tcp://bla:61616,tcp://bla:61617)"),
+                new URI("failover://(tcp://localhost:61616,ssl://anotherhost:61617)") };
+        for (URI uri : compositeURIs) {
+            assertTrue(uri + " must be detected as composite URI", URISupport.isCompositeURI(uri));
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/resources/keystore
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/resources/keystore b/qpid-jms-client/src/test/resources/keystore
new file mode 100644
index 0000000..9ee6adf
Binary files /dev/null and b/qpid-jms-client/src/test/resources/keystore differ

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/resources/log4j.properties b/qpid-jms-client/src/test/resources/log4j.properties
new file mode 100644
index 0000000..8df5a9e
--- /dev/null
+++ b/qpid-jms-client/src/test/resources/log4j.properties
@@ -0,0 +1,38 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+#
+# The logging properties used during tests..
+#
+log4j.rootLogger=INFO, out, stdout
+
+log4j.logger.org.apache.qpid.jms=DEBUG
+
+# Tune the TestPeer as needed for debugging.
+log4j.logger.org.apache.qpid.jms.test.testpeer=TRACE
+
+# CONSOLE appender not used by default
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n
+
+# File appender
+log4j.appender.out=org.apache.log4j.FileAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] - %-5p %-30.30c{1} - %m%n
+log4j.appender.out.file=target/activemq-test.log
+log4j.appender.out.append=true

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/.gitignore
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/.gitignore b/qpid-jms-discovery/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/qpid-jms-discovery/.gitignore
@@ -0,0 +1 @@
+/target

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/pom.xml b/qpid-jms-discovery/pom.xml
new file mode 100644
index 0000000..58204cf
--- /dev/null
+++ b/qpid-jms-discovery/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>qpid-jms-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>qpid-jms-discovery</artifactId>
+  <name>QpidJMS Discovery Library</name>
+  <description>The Broker Discovery module for QpidJMS</description>
+  <packaging>jar</packaging>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <!-- =================================== -->
+    <!-- Required Dependencies                -->
+    <!-- =================================== -->
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>qpid-jms-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+
+    <!-- =================================== -->
+    <!-- Testing Dependencies                -->
+    <!-- =================================== -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-broker</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-kahadb-store</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-amqp</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-jaas</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-spring</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java
new file mode 100644
index 0000000..051f567
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgent.java
@@ -0,0 +1,63 @@
+/**
+ * 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.jms.provider.discovery;
+
+import java.io.IOException;
+
+/**
+ * Interface for all agents used to detect instances of remote peers on the network.
+ */
+public interface DiscoveryAgent {
+
+    /**
+     * Sets the discovery listener
+     *
+     * @param listener
+     *        the listener to notify on discovery events, or null to clear.
+     */
+    void setDiscoveryListener(DiscoveryListener listener);
+
+    /**
+     * Starts the agent after which new remote peers can start to be found.
+     *
+     * @throws IOException if an IO error occurs while starting the agent.
+     * @throws IllegalStateException if the agent is not properly configured.
+     */
+    void start() throws IOException, IllegalStateException;
+
+    /**
+     * Stops the agent after which no new remote peers will be found.  This
+     * method should attempt to close any agent resources and if an error occurs
+     * it should handle it and not re-throw to the calling entity.
+     */
+    void close();
+
+    /**
+     * Suspends the Agent which suppresses any new attempts to discover remote
+     * peers until the agent is resumed.  If the service is not able to be suspended
+     * then this method should not throw an Exception, simply return as if successful.
+     */
+    void suspend();
+
+    /**
+     * Resumes discovery by this agent if it was previously suspended.  If the agent
+     * does not support being suspended or is closed this method should simply return
+     * without throwing any exceptions.
+     */
+    void resume();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.java
new file mode 100644
index 0000000..f37745c
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryAgentFactory.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.jms.provider.discovery;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.qpid.jms.util.FactoryFinder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory used to find and create instances of DiscoveryAgent using the name
+ * of the desired agent to locate it's factory class definition file.
+ */
+public abstract class DiscoveryAgentFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DiscoveryAgentFactory.class);
+
+    private static final FactoryFinder<DiscoveryAgentFactory> AGENT_FACTORY_FINDER =
+        new FactoryFinder<DiscoveryAgentFactory>(DiscoveryAgentFactory.class,
+            "META-INF/services/org/apache/qpid/jms/provider/agents/");
+
+    /**
+     * Creates an instance of the given DiscoveryAgent and configures it using the
+     * properties set on the given remote broker URI.
+     *
+     * @param remoteURI
+     *        The URI used to configure remote discovery.
+     *
+     * @return a new DiscoveryAgent instance.
+     *
+     * @throws Exception if an error occurs while creating the DiscoveryAgent instance.
+     */
+    public abstract DiscoveryAgent createDiscoveryAgent(URI remoteURI) throws Exception;
+
+    /**
+     * @return the name of this discovery agent, e.g. Multicast, Zeroconf, etc.
+     */
+    public abstract String getName();
+
+    /**
+     * Static create method that performs the DiscoveryAgent search and handles the
+     * configuration and setup.
+     *
+     * @param remoteURI
+     *        the URI used to configure the discovery mechanism.
+     *
+     * @return a new DiscoveryAgent instance that is ready for use.
+     *
+     * @throws Exception if an error occurs while creating the DiscoveryAgent instance.
+     */
+    public static DiscoveryAgent createAgent(URI remoteURI) throws Exception {
+        DiscoveryAgent result = null;
+
+        try {
+            DiscoveryAgentFactory factory = findAgentFactory(remoteURI);
+            result = factory.createDiscoveryAgent(remoteURI);
+        } catch (Exception ex) {
+            LOG.error("Failed to create DiscoveryAgent instance for: {}", remoteURI.getScheme());
+            LOG.trace("Error: ", ex);
+            throw ex;
+        }
+
+        return result;
+    }
+
+    /**
+     * Searches for a DiscoveryAgentFactory by using the scheme from the given URI.
+     *
+     * The search first checks the local cache of discovery agent factories before moving on
+     * to search in the classpath.
+     *
+     * @param location
+     *        The URI whose scheme will be used to locate a DiscoveryAgentFactory.
+     *
+     * @return a DiscoveryAgentFactory instance matching the URI's scheme.
+     *
+     * @throws IOException if an error occurs while locating the factory.
+     */
+    protected static DiscoveryAgentFactory findAgentFactory(URI location) throws IOException {
+        String scheme = location.getScheme();
+        if (scheme == null) {
+            throw new IOException("No Discovery Agent scheme specified: [" + location + "]");
+        }
+
+        DiscoveryAgentFactory factory = null;
+        if (factory == null) {
+            try {
+                factory = AGENT_FACTORY_FINDER.newInstance(scheme);
+            } catch (Throwable e) {
+                throw new IOException("Discovery Agent scheme NOT recognized: [" + scheme + "]", e);
+            }
+        }
+
+        return factory;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java
new file mode 100644
index 0000000..0fc2f29
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryEvent.java
@@ -0,0 +1,45 @@
+/**
+ * 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.jms.provider.discovery;
+
+/**
+ * Event class used to convey discovered remote peer information to the
+ * DiscoveryProvider.
+ */
+public class DiscoveryEvent {
+
+    public enum EventType {
+        ALIVE,
+        SHUTDOWN
+    };
+
+    private final String peerUri;
+    private final EventType type;
+
+    public DiscoveryEvent(String peerUri, EventType type) {
+        this.peerUri = peerUri;
+        this.type = type;
+    }
+
+    public String getPeerUri() {
+        return peerUri;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java
new file mode 100644
index 0000000..07e9895
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryListener.java
@@ -0,0 +1,40 @@
+/**
+ * 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.jms.provider.discovery;
+
+/**
+ * A listener of services being added or removed from a network
+ */
+public interface DiscoveryListener {
+
+    /**
+     * Called when a DiscoveryAgent becomes aware of a new remote peer.
+     *
+     * @param event
+     *        the event data which contains the peer address and optional name.
+     */
+    void onServiceAdd(DiscoveryEvent event);
+
+    /**
+     * Called when a DiscoveryAgent can no longer detect a previously known remote peer.
+     *
+     * @param event
+     *        the event data which contains the peer address and optional name.
+     */
+    void onServiceRemove(DiscoveryEvent event);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java
new file mode 100644
index 0000000..1d3a0f0
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProvider.java
@@ -0,0 +1,139 @@
+/**
+ * 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.jms.provider.discovery;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.qpid.jms.provider.ProviderWrapper;
+import org.apache.qpid.jms.provider.failover.FailoverProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An AsyncProvider instance that wraps the FailoverProvider and listens for
+ * events about discovered remote peers using a configured DiscoveryAgent
+ * instance.
+ */
+public class DiscoveryProvider extends ProviderWrapper<FailoverProvider> implements DiscoveryListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DiscoveryProviderFactory.class);
+
+    private final URI discoveryUri;
+    private DiscoveryAgent discoveryAgent;
+    private final ConcurrentHashMap<String, URI> serviceURIs = new ConcurrentHashMap<String, URI>();
+
+    /**
+     * Creates a new instance of the DiscoveryProvider.
+     *
+     * The Provider is created and initialized with the original URI used to create it,
+     * and an instance of a FailoverProcider which it will use to initiate and maintain
+     * connections to the discovered peers.
+     *
+     * @param discoveryUri
+     * @param next
+     */
+    public DiscoveryProvider(URI discoveryUri, FailoverProvider next) {
+        super(next);
+        this.discoveryUri = discoveryUri;
+    }
+
+    @Override
+    public void start() throws IOException, IllegalStateException {
+        if (this.discoveryAgent == null) {
+            throw new IllegalStateException("No DiscoveryAgent configured.");
+        }
+
+        discoveryAgent.setDiscoveryListener(this);
+        discoveryAgent.start();
+
+        super.start();
+    }
+
+    @Override
+    public void close() {
+        discoveryAgent.close();
+        super.close();
+    }
+
+    //------------------- Property Accessors ---------------------------------//
+
+    /**
+     * @return the original URI used to configure this DiscoveryProvider.
+     */
+    public URI getDiscoveryURI() {
+        return this.discoveryUri;
+    }
+
+    /**
+     * @return the configured DiscoveryAgent instance used by this DiscoveryProvider.
+     */
+    public DiscoveryAgent getDiscoveryAgent() {
+        return this.discoveryAgent;
+    }
+
+    /**
+     * Sets the discovery agent used by this provider to locate remote peer instance.
+     *
+     * @param agent
+     *        the agent to use to discover remote peers
+     */
+    public void setDiscoveryAgent(DiscoveryAgent agent) {
+        this.discoveryAgent = agent;
+    }
+
+    //------------------- Discovery Event Handlers ---------------------------//
+
+    @Override
+    public void onServiceAdd(DiscoveryEvent event) {
+        String url = event.getPeerUri();
+        if (url != null) {
+            try {
+                URI uri = new URI(url);
+                LOG.info("Adding new peer connection URL: {}", uri);
+                serviceURIs.put(event.getPeerUri(), uri);
+                next.add(uri);
+            } catch (URISyntaxException e) {
+                LOG.warn("Could not add remote URI: {} due to bad URI syntax: {}", url, e.getMessage());
+            }
+        }
+    }
+
+    @Override
+    public void onServiceRemove(DiscoveryEvent event) {
+        URI uri = serviceURIs.get(event.getPeerUri());
+        if (uri != null) {
+            next.remove(uri);
+        }
+    }
+
+    //------------------- Connection State Handlers --------------------------//
+
+    @Override
+    public void onConnectionInterrupted(URI remoteURI) {
+        this.discoveryAgent.resume();
+        super.onConnectionInterrupted(remoteURI);
+    }
+
+    @Override
+    public void onConnectionRestored(URI remoteURI) {
+        this.discoveryAgent.suspend();
+        super.onConnectionRestored(remoteURI);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.java
new file mode 100644
index 0000000..cd2ab5a
--- /dev/null
+++ b/qpid-jms-discovery/src/main/java/org/apache/qpid/jms/provider/discovery/DiscoveryProviderFactory.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.jms.provider.discovery;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFactory;
+import org.apache.qpid.jms.provider.failover.FailoverProvider;
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+import org.apache.qpid.jms.util.URISupport.CompositeData;
+
+/**
+ * Factory for creating the Discovery Provider
+ */
+public class DiscoveryProviderFactory extends ProviderFactory {
+
+    private static final String DISCOVERED_OPTION_PREFIX = "discovered.";
+
+    @Override
+    public Provider createAsyncProvider(URI remoteURI) throws Exception {
+
+        CompositeData composite = URISupport.parseComposite(remoteURI);
+        Map<String, String> options = composite.getParameters();
+
+        // Failover will apply the nested options to each URI while attempting to connect.
+        Map<String, String> nested = PropertyUtil.filterProperties(options, DISCOVERED_OPTION_PREFIX);
+        FailoverProvider failover = new FailoverProvider(nested);
+        PropertyUtil.setProperties(failover, options);
+
+        // TODO - Revisit URI options setting and enhance the ProperyUtils to provide a
+        //        means of setting some properties on a object and obtaining the leftovers
+        //        so we can pass those along to the next until we consume them all or we
+        //        have leftovers which implies a bad URI.
+
+        DiscoveryProvider discovery = new DiscoveryProvider(remoteURI, failover);
+        PropertyUtil.setProperties(discovery, options);
+
+        DiscoveryAgent agent = DiscoveryAgentFactory.createAgent(composite.getComponents()[0]);
+        discovery.setDiscoveryAgent(agent);
+
+        return discovery;
+    }
+
+    @Override
+    public String getName() {
+        return "Discovery";
+    }
+}


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


[26/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
new file mode 100644
index 0000000..b4d03af
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnection.java
@@ -0,0 +1,1128 @@
+/**
+ * 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.jms;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionConsumer;
+import javax.jms.ConnectionMetaData;
+import javax.jms.Destination;
+import javax.jms.ExceptionListener;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueSession;
+import javax.jms.ServerSessionPool;
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicSession;
+import javax.net.ssl.SSLContext;
+
+import org.apache.qpid.jms.exceptions.JmsConnectionFailedException;
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConnectionId;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.meta.JmsTransactionId;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderClosedException;
+import org.apache.qpid.jms.provider.ProviderFuture;
+import org.apache.qpid.jms.provider.ProviderListener;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+import org.apache.qpid.jms.util.IdGenerator;
+import org.apache.qpid.jms.util.ThreadPoolUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of a JMS Connection
+ */
+public class JmsConnection implements Connection, TopicConnection, QueueConnection, ProviderListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsConnection.class);
+
+    private JmsConnectionInfo connectionInfo;
+
+    private final IdGenerator clientIdGenerator;
+    private boolean clientIdSet;
+    private boolean sendAcksAsync;
+    private ExceptionListener exceptionListener;
+    private final List<JmsSession> sessions = new CopyOnWriteArrayList<JmsSession>();
+    private final Map<JmsConsumerId, JmsMessageDispatcher> dispatchers =
+        new ConcurrentHashMap<JmsConsumerId, JmsMessageDispatcher>();
+    private final AtomicBoolean connected = new AtomicBoolean();
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private final AtomicBoolean closing = new AtomicBoolean();
+    private final AtomicBoolean started = new AtomicBoolean();
+    private final AtomicBoolean failed = new AtomicBoolean();
+    private final Object connectLock = new Object();
+    private IOException firstFailureError;
+    private JmsPrefetchPolicy prefetchPolicy = new JmsPrefetchPolicy();
+    private boolean messagePrioritySupported;
+
+    private final ThreadPoolExecutor executor;
+
+    private URI brokerURI;
+    private URI localURI;
+    private SSLContext sslContext;
+    private Provider provider;
+    private final Set<JmsConnectionListener> connectionListeners =
+        new CopyOnWriteArraySet<JmsConnectionListener>();
+    private final Map<JmsDestination, JmsDestination> tempDestinations =
+        new ConcurrentHashMap<JmsDestination, JmsDestination>();
+    private final AtomicLong sessionIdGenerator = new AtomicLong();
+    private final AtomicLong tempDestIdGenerator = new AtomicLong();
+    private final AtomicLong transactionIdGenerator = new AtomicLong();
+    private JmsMessageFactory messageFactory;
+
+    protected JmsConnection(String connectionId, Provider provider, IdGenerator clientIdGenerator) throws JMSException {
+
+        // This executor can be used for dispatching asynchronous tasks that might block or result
+        // in reentrant calls to this Connection that could block.  The thread in this executor
+        // will also serve as a means of preventing JVM shutdown should a client application
+        // not have it's own mechanism for doing so.
+        executor = new ThreadPoolExecutor(1, 1, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread thread = new Thread(r, "QpidJMS Connection Executor: ");
+                return thread;
+            }
+        });
+
+        this.provider = provider;
+        this.provider.setProviderListener(this);
+        try {
+            this.provider.start();
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+
+        this.clientIdGenerator = clientIdGenerator;
+        this.connectionInfo = new JmsConnectionInfo(new JmsConnectionId(connectionId));
+    }
+
+    /**
+     * @throws JMSException
+     * @see javax.jms.Connection#close()
+     */
+    @Override
+    public void close() throws JMSException {
+        boolean interrupted = Thread.interrupted();
+
+        try {
+
+            if (!closed.get() && !failed.get()) {
+                // do not fail if already closed as specified by the JMS specification.
+                doStop(false);
+            }
+
+            synchronized (this) {
+
+                if (closed.get()) {
+                    return;
+                }
+
+                closing.set(true);
+
+                for (JmsSession session : this.sessions) {
+                    session.shutdown();
+                }
+
+                this.sessions.clear();
+                this.tempDestinations.clear();
+
+                if (isConnected() && !failed.get()) {
+                    ProviderFuture request = new ProviderFuture();
+                    try {
+                        provider.destroy(connectionInfo, request);
+
+                        try {
+                            request.sync();
+                        } catch (Exception ex) {
+                            // TODO - Spec is a bit vague here, we don't fail if already closed but
+                            //        in this case we really aren't closed yet so there could be an
+                            //        argument that at this point an exception is still valid.
+                            if (ex.getCause() instanceof InterruptedException) {
+                                throw (InterruptedException) ex.getCause();
+                            }
+                            LOG.debug("Failed destroying Connection resource: {}", ex.getMessage());
+                        }
+                    } catch(ProviderClosedException pce) {
+                        LOG.debug("Ignoring provider closed exception during connection close");
+                    }
+                }
+
+                connected.set(false);
+                started.set(false);
+                closing.set(false);
+                closed.set(true);
+            }
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        } finally {
+            try {
+                ThreadPoolUtils.shutdown(executor);
+            } catch (Throwable e) {
+                LOG.warn("Error shutting down thread pool: " + executor + ". This exception will be ignored.", e);
+            }
+
+            if (provider != null) {
+                provider.close();
+                provider = null;
+            }
+
+            if (interrupted) {
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * Called to free all Connection resources.
+     */
+    protected void shutdown() throws JMSException {
+
+        // TODO - Once ConnectionConsumer is added we must shutdown those as well.
+
+        for (JmsSession session : this.sessions) {
+            session.shutdown();
+        }
+
+        if (isConnected() && !failed.get() && !closing.get()) {
+            destroyResource(connectionInfo);
+        }
+
+        if (clientIdSet) {
+            connectionInfo.setClientId(null);
+            clientIdSet = false;
+        }
+
+        tempDestinations.clear();
+        started.set(false);
+        connected.set(false);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @param sessionPool
+     * @param maxMessages
+     * @return ConnectionConsumer
+     * @throws JMSException
+     * @see javax.jms.Connection#createConnectionConsumer(javax.jms.Destination,
+     *      java.lang.String, javax.jms.ServerSessionPool, int)
+     */
+    @Override
+    public ConnectionConsumer createConnectionConsumer(Destination destination, String messageSelector,
+                                                       ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        throw new JMSException("Not supported");
+    }
+
+    /**
+     * @param topic
+     * @param subscriptionName
+     * @param messageSelector
+     * @param sessionPool
+     * @param maxMessages
+     * @return ConnectionConsumer
+     * @throws JMSException
+     *
+     * @see javax.jms.Connection#createDurableConnectionConsumer(javax.jms.Topic,
+     *      java.lang.String, java.lang.String, javax.jms.ServerSessionPool, int)
+     */
+    @Override
+    public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String subscriptionName,
+                                                              String messageSelector, ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        throw new JMSException("Not supported");
+    }
+
+    /**
+     * @param transacted
+     * @param acknowledgeMode
+     * @return Session
+     * @throws JMSException
+     * @see javax.jms.Connection#createSession(boolean, int)
+     */
+    @Override
+    public Session createSession(boolean transacted, int acknowledgeMode) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        int ackMode = getSessionAcknowledgeMode(transacted, acknowledgeMode);
+        JmsSession result = new JmsSession(this, getNextSessionId(), ackMode);
+        addSession(result);
+        if (started.get()) {
+            result.start();
+        }
+        return result;
+    }
+
+    /**
+     * @return clientId
+     * @see javax.jms.Connection#getClientID()
+     */
+    @Override
+    public String getClientID() throws JMSException {
+        checkClosedOrFailed();
+        return this.connectionInfo.getClientId();
+    }
+
+    /**
+     * @return connectionInfoData
+     * @see javax.jms.Connection#getMetaData()
+     */
+    @Override
+    public ConnectionMetaData getMetaData() throws JMSException {
+        checkClosedOrFailed();
+        return JmsConnectionMetaData.INSTANCE;
+    }
+
+    /**
+     * @param clientID
+     * @throws JMSException
+     * @see javax.jms.Connection#setClientID(java.lang.String)
+     */
+    @Override
+    public synchronized void setClientID(String clientID) throws JMSException {
+        checkClosedOrFailed();
+
+        if (this.clientIdSet) {
+            throw new IllegalStateException("The clientID has already been set");
+        }
+        if (clientID == null) {
+            throw new IllegalStateException("Cannot have a null clientID");
+        }
+        if (connected.get()) {
+            throw new IllegalStateException("Cannot set the client id once connected.");
+        }
+
+        this.connectionInfo.setClientId(clientID);
+        this.clientIdSet = true;
+
+        //We weren't connected if we got this far, we should now connect now to ensure the clientID is valid.
+        //TODO: determine if any resulting failure is only the result of the ClientID value, or other reasons such as auth.
+        connect();
+    }
+
+    /**
+     * @throws JMSException
+     * @see javax.jms.Connection#start()
+     */
+    @Override
+    public void start() throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        if (this.started.compareAndSet(false, true)) {
+            try {
+                for (JmsSession s : this.sessions) {
+                    s.start();
+                }
+            } catch (Exception e) {
+                throw JmsExceptionSupport.create(e);
+            }
+        }
+    }
+
+    /**
+     * @throws JMSException
+     * @see javax.jms.Connection#stop()
+     */
+    @Override
+    public void stop() throws JMSException {
+        doStop(true);
+    }
+
+    /**
+     * @see #stop()
+     * @param checkClosed <tt>true</tt> to check for already closed and throw
+     *                    {@link java.lang.IllegalStateException} if already closed,
+     *                    <tt>false</tt> to skip this check
+     * @throws JMSException if the JMS provider fails to stop message delivery due to some internal error.
+     */
+    void doStop(boolean checkClosed) throws JMSException {
+        if (checkClosed) {
+            checkClosedOrFailed();
+        }
+        if (started.compareAndSet(true, false)) {
+            synchronized(sessions) {
+                for (JmsSession s : this.sessions) {
+                    s.stop();
+                }
+            }
+        }
+    }
+
+    /**
+     * @param topic
+     * @param messageSelector
+     * @param sessionPool
+     * @param maxMessages
+     * @return ConnectionConsumer
+     * @throws JMSException
+     * @see javax.jms.TopicConnection#createConnectionConsumer(javax.jms.Topic,
+     *      java.lang.String, javax.jms.ServerSessionPool, int)
+     */
+    @Override
+    public ConnectionConsumer createConnectionConsumer(Topic topic, String messageSelector,
+                                                       ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        return null;
+    }
+
+    /**
+     * @param transacted
+     * @param acknowledgeMode
+     * @return TopicSession
+     * @throws JMSException
+     * @see javax.jms.TopicConnection#createTopicSession(boolean, int)
+     */
+    @Override
+    public TopicSession createTopicSession(boolean transacted, int acknowledgeMode) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        int ackMode = getSessionAcknowledgeMode(transacted, acknowledgeMode);
+        JmsTopicSession result = new JmsTopicSession(this, getNextSessionId(), ackMode);
+        addSession(result);
+        if (started.get()) {
+            result.start();
+        }
+        return result;
+    }
+
+    /**
+     * @param queue
+     * @param messageSelector
+     * @param sessionPool
+     * @param maxMessages
+     * @return ConnectionConsumer
+     * @throws JMSException
+     * @see javax.jms.QueueConnection#createConnectionConsumer(javax.jms.Queue,
+     *      java.lang.String, javax.jms.ServerSessionPool, int)
+     */
+    @Override
+    public ConnectionConsumer createConnectionConsumer(Queue queue, String messageSelector,
+                                                       ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        return null;
+    }
+
+    /**
+     * @param transacted
+     * @param acknowledgeMode
+     * @return QueueSession
+     * @throws JMSException
+     * @see javax.jms.QueueConnection#createQueueSession(boolean, int)
+     */
+    @Override
+    public QueueSession createQueueSession(boolean transacted, int acknowledgeMode) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+        int ackMode = getSessionAcknowledgeMode(transacted, acknowledgeMode);
+        JmsQueueSession result = new JmsQueueSession(this, getNextSessionId(), ackMode);
+        addSession(result);
+        if (started.get()) {
+            result.start();
+        }
+        return result;
+    }
+
+    /**
+     * @param ex
+     */
+    public void onException(Exception ex) {
+        onException(JmsExceptionSupport.create(ex));
+    }
+
+    /**
+     * @param ex
+     */
+    public void onException(JMSException ex) {
+        ExceptionListener l = this.exceptionListener;
+        if (l != null) {
+            l.onException(JmsExceptionSupport.create(ex));
+        }
+    }
+
+    protected int getSessionAcknowledgeMode(boolean transacted, int acknowledgeMode) throws JMSException {
+        int result = acknowledgeMode;
+        if (!transacted && acknowledgeMode == Session.SESSION_TRANSACTED) {
+            throw new JMSException("acknowledgeMode SESSION_TRANSACTED cannot be used for an non-transacted Session");
+        }
+        if (transacted) {
+            result = Session.SESSION_TRANSACTED;
+        }
+        return result;
+    }
+
+    protected void removeSession(JmsSession session) throws JMSException {
+        this.sessions.remove(session);
+    }
+
+    protected void addSession(JmsSession s) {
+        this.sessions.add(s);
+    }
+
+    protected void addDispatcher(JmsConsumerId consumerId, JmsMessageDispatcher dispatcher) {
+        dispatchers.put(consumerId, dispatcher);
+    }
+
+    protected void removeDispatcher(JmsConsumerId consumerId) {
+        dispatchers.remove(consumerId);
+    }
+
+    private void connect() throws JMSException {
+        synchronized(this.connectLock) {
+            if (isConnected() || closed.get()) {
+                return;
+            }
+
+            if (connectionInfo.getClientId() == null || connectionInfo.getClientId().trim().isEmpty()) {
+                connectionInfo.setClientId(clientIdGenerator.generateId());
+            }
+
+            this.connectionInfo = createResource(connectionInfo);
+            this.connected.set(true);
+            this.messageFactory = provider.getMessageFactory();
+
+            // TODO - Advisory Support.
+            //
+            // Providers should have an interface for adding a listener for temporary
+            // destination advisory messages for create / destroy so we can track them
+            // and throw exceptions when producers try to send to deleted destinations.
+        }
+    }
+
+    /**
+     * @return a newly initialized TemporaryQueue instance.
+     */
+    protected TemporaryQueue createTemporaryQueue() throws JMSException {
+        String destinationName = connectionInfo.getConnectionId() + ":" + tempDestIdGenerator.incrementAndGet();
+        JmsTemporaryQueue queue = new JmsTemporaryQueue(destinationName);
+        queue = createResource(queue);
+        tempDestinations.put(queue, queue);
+        return queue;
+    }
+
+    /**
+     * @return a newly initialized TemporaryTopic instance.
+     */
+    protected TemporaryTopic createTemporaryTopic() throws JMSException {
+        String destinationName = connectionInfo.getConnectionId() + ":" + tempDestIdGenerator.incrementAndGet();
+        JmsTemporaryTopic topic = new JmsTemporaryTopic(destinationName);
+        topic = createResource(topic);
+        tempDestinations.put(topic, topic);
+        return topic;
+    }
+
+    protected void deleteDestination(JmsDestination destination) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+
+            for (JmsSession session : this.sessions) {
+                if (session.isDestinationInUse(destination)) {
+                    throw new JMSException("A consumer is consuming from the temporary destination");
+                }
+            }
+
+            if (destination.isTemporary()) {
+                tempDestinations.remove(destination);
+            }
+
+            destroyResource(destination);
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    protected void checkClosedOrFailed() throws JMSException {
+        checkClosed();
+        if (failed.get()) {
+            throw new JmsConnectionFailedException(firstFailureError);
+        }
+    }
+
+    protected void checkClosed() throws IllegalStateException {
+        if (this.closed.get()) {
+            throw new IllegalStateException("The Connection is closed");
+        }
+    }
+
+    protected JmsSessionId getNextSessionId() {
+        return new JmsSessionId(connectionInfo.getConnectionId(), sessionIdGenerator.incrementAndGet());
+    }
+
+    protected JmsTransactionId getNextTransactionId() {
+        return new JmsTransactionId(connectionInfo.getConnectionId(), transactionIdGenerator.incrementAndGet());
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Provider interface methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    <T extends JmsResource> T createResource(T resource) throws JMSException {
+        checkClosedOrFailed();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.create(resource, request);
+            request.sync();
+            return resource;
+        } catch (Exception ex) {
+            throw JmsExceptionSupport.create(ex);
+        }
+    }
+
+    void startResource(JmsResource resource) throws JMSException {
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.start(resource, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void destroyResource(JmsResource resource) throws JMSException {
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.destroy(resource, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void send(JmsOutboundMessageDispatch envelope) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        // TODO - We don't currently have a way to say that an operation
+        //        should be done asynchronously.  A send can be done async
+        //        in many cases, such as non-persistent delivery.  We probably
+        //        don't need to do anything here though just have a way to
+        //        configure the provider for async sends which we do in the
+        //        JmsConnectionInfo.  Here we just need to register a listener
+        //        on the request to know when it completes if we want to do
+        //        JMS 2.0 style async sends where we signal a callback, then
+        //        we can manage order of callback events to async senders at
+        //        this level.
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.send(envelope, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void acknowledge(JmsInboundMessageDispatch envelope, ACK_TYPE ackType) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.acknowledge(envelope, ackType, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void acknowledge(JmsSessionId sessionId) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.acknowledge(sessionId, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void unsubscribe(String name) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.unsubscribe(name, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void commit(JmsSessionId sessionId) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.commit(sessionId, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void rollback(JmsSessionId sessionId) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.rollback(sessionId, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void recover(JmsSessionId sessionId) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.recover(sessionId, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    void pull(JmsConsumerId consumerId, long timeout) throws JMSException {
+        checkClosedOrFailed();
+        connect();
+
+        try {
+            ProviderFuture request = new ProviderFuture();
+            provider.pull(consumerId, timeout, request);
+            request.sync();
+        } catch (Exception ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Property setters and getters
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @return ExceptionListener
+     * @see javax.jms.Connection#getExceptionListener()
+     */
+    @Override
+    public ExceptionListener getExceptionListener() throws JMSException {
+        checkClosedOrFailed();
+        return this.exceptionListener;
+    }
+
+    /**
+     * @param listener
+     * @see javax.jms.Connection#setExceptionListener(javax.jms.ExceptionListener)
+     */
+    @Override
+    public void setExceptionListener(ExceptionListener listener) throws JMSException {
+        checkClosedOrFailed();
+        this.exceptionListener = listener;
+    }
+
+    /**
+     * Adds a JmsConnectionListener so that a client can be notified of events in
+     * the underlying protocol provider.
+     *
+     * @param listener
+     *        the new listener to add to the collection.
+     */
+    public void addConnectionListener(JmsConnectionListener listener) {
+        this.connectionListeners.add(listener);
+    }
+
+    /**
+     * Removes a JmsConnectionListener that was previously registered.
+     *
+     * @param listener
+     *        the listener to remove from the collection.
+     */
+    public void removeTransportListener(JmsConnectionListener listener) {
+        this.connectionListeners.remove(listener);
+    }
+
+    public boolean isForceAsyncSend() {
+        return connectionInfo.isForceAsyncSend();
+    }
+
+    public void setForceAsyncSend(boolean forceAsyncSend) {
+        connectionInfo.setForceAsyncSends(forceAsyncSend);
+    }
+
+    public boolean isAlwaysSyncSend() {
+        return connectionInfo.isAlwaysSyncSend();
+    }
+
+    public void setAlwaysSyncSend(boolean alwaysSyncSend) {
+        this.connectionInfo.setAlwaysSyncSend(alwaysSyncSend);
+    }
+
+    public String getTopicPrefix() {
+        return connectionInfo.getTopicPrefix();
+    }
+
+    public void setTopicPrefix(String topicPrefix) {
+        connectionInfo.setTopicPrefix(topicPrefix);
+    }
+
+    public String getTempTopicPrefix() {
+        return connectionInfo.getTempTopicPrefix();
+    }
+
+    public void setTempTopicPrefix(String tempTopicPrefix) {
+        connectionInfo.setTempTopicPrefix(tempTopicPrefix);
+    }
+
+    public String getTempQueuePrefix() {
+        return connectionInfo.getTempQueuePrefix();
+    }
+
+    public void setTempQueuePrefix(String tempQueuePrefix) {
+        connectionInfo.setTempQueuePrefix(tempQueuePrefix);
+    }
+
+    public String getQueuePrefix() {
+        return connectionInfo.getQueuePrefix();
+    }
+
+    public void setQueuePrefix(String queuePrefix) {
+        connectionInfo.setQueuePrefix(queuePrefix);
+    }
+
+    public boolean isOmitHost() {
+        return connectionInfo.isOmitHost();
+    }
+
+    public void setOmitHost(boolean omitHost) {
+        connectionInfo.setOmitHost(omitHost);
+    }
+
+    public JmsPrefetchPolicy getPrefetchPolicy() {
+        return prefetchPolicy;
+    }
+
+    public void setPrefetchPolicy(JmsPrefetchPolicy prefetchPolicy) {
+        this.prefetchPolicy = prefetchPolicy;
+    }
+
+    public boolean isMessagePrioritySupported() {
+        return messagePrioritySupported;
+    }
+
+    public void setMessagePrioritySupported(boolean messagePrioritySupported) {
+        this.messagePrioritySupported = messagePrioritySupported;
+    }
+
+    public long getCloseTimeout() {
+        return connectionInfo.getCloseTimeout();
+    }
+
+    public void setCloseTimeout(long closeTimeout) {
+        connectionInfo.setCloseTimeout(closeTimeout);
+    }
+
+    public long getConnectTimeout() {
+        return this.connectionInfo.getConnectTimeout();
+    }
+
+    public void setConnectTimeout(long connectTimeout) {
+        this.connectionInfo.setConnectTimeout(connectTimeout);
+    }
+
+    public long getSendTimeout() {
+        return connectionInfo.getSendTimeout();
+    }
+
+    public void setSendTimeout(long sendTimeout) {
+        connectionInfo.setSendTimeout(sendTimeout);
+    }
+
+    public long getRequestTimeout() {
+        return connectionInfo.getRequestTimeout();
+    }
+
+    public void setRequestTimeout(long requestTimeout) {
+        connectionInfo.setRequestTimeout(requestTimeout);
+    }
+
+    public URI getBrokerURI() {
+        return brokerURI;
+    }
+
+    public void setBrokerURI(URI brokerURI) {
+        this.brokerURI = brokerURI;
+    }
+
+    public URI getLocalURI() {
+        return localURI;
+    }
+
+    public void setLocalURI(URI localURI) {
+        this.localURI = localURI;
+    }
+
+    public SSLContext getSslContext() {
+        return sslContext;
+    }
+
+    public void setSslContext(SSLContext sslContext) {
+        this.sslContext = sslContext;
+    }
+
+    public String getUsername() {
+        return this.connectionInfo.getUsername();
+    }
+
+    public void setUsername(String username) {
+        this.connectionInfo.setUsername(username);;
+    }
+
+    public String getPassword() {
+        return this.connectionInfo.getPassword();
+    }
+
+    public void setPassword(String password) {
+        this.connectionInfo.setPassword(password);
+    }
+
+    public Provider getProvider() {
+        return provider;
+    }
+
+    void setProvider(Provider provider) {
+        this.provider = provider;
+    }
+
+    public boolean isConnected() {
+        return this.connected.get();
+    }
+
+    public boolean isStarted() {
+        return this.started.get();
+    }
+
+    public boolean isClosed() {
+        return this.closed.get();
+    }
+
+    JmsConnectionId getConnectionId() {
+        return this.connectionInfo.getConnectionId();
+    }
+
+    public boolean isWatchRemoteDestinations() {
+        return this.connectionInfo.isWatchRemoteDestinations();
+    }
+
+    public void setWatchRemoteDestinations(boolean watchRemoteDestinations) {
+        this.connectionInfo.setWatchRemoteDestinations(watchRemoteDestinations);
+    }
+
+    public JmsMessageFactory getMessageFactory() {
+        return messageFactory;
+    }
+
+    public boolean isSendAcksAsync() {
+        return sendAcksAsync;
+    }
+
+    public void setSendAcksAsync(boolean sendAcksAsync) {
+        this.sendAcksAsync = sendAcksAsync;
+    }
+
+    @Override
+    public void onMessage(JmsInboundMessageDispatch envelope) {
+
+        JmsMessage incoming = envelope.getMessage();
+        // Ensure incoming Messages are in readonly mode.
+        if (incoming != null) {
+            incoming.setReadOnlyBody(true);
+            incoming.setReadOnlyProperties(true);
+        }
+
+        JmsMessageDispatcher dispatcher = dispatchers.get(envelope.getConsumerId());
+        if (dispatcher != null) {
+            dispatcher.onMessage(envelope);
+        }
+        for (JmsConnectionListener listener : connectionListeners) {
+            listener.onMessage(envelope);
+        }
+    }
+
+    @Override
+    public void onConnectionInterrupted(URI remoteURI) {
+        for (JmsSession session : sessions) {
+            session.onConnectionInterrupted();
+        }
+
+        for (JmsConnectionListener listener : connectionListeners) {
+            listener.onConnectionInterrupted(remoteURI);
+        }
+    }
+
+    @Override
+    public void onConnectionRecovery(Provider provider) throws Exception {
+        // TODO - Recover Advisory Consumer once we can support it.
+
+        LOG.debug("Connection {} is starting recovery.", connectionInfo.getConnectionId());
+
+        ProviderFuture request = new ProviderFuture();
+        provider.create(connectionInfo, request);
+        request.sync();
+
+        for (JmsDestination tempDestination : tempDestinations.values()) {
+            createResource(tempDestination);
+        }
+
+        for (JmsSession session : sessions) {
+            session.onConnectionRecovery(provider);
+        }
+    }
+
+    @Override
+    public void onConnectionRecovered(Provider provider) throws Exception {
+        LOG.debug("Connection {} is finalizing recovery.", connectionInfo.getConnectionId());
+
+        this.messageFactory = provider.getMessageFactory();
+
+        for (JmsSession session : sessions) {
+            session.onConnectionRecovered(provider);
+        }
+    }
+
+    @Override
+    public void onConnectionRestored(URI remoteURI) {
+        for (JmsSession session : sessions) {
+            session.onConnectionRestored();
+        }
+
+        for (JmsConnectionListener listener : connectionListeners) {
+            listener.onConnectionRestored(remoteURI);
+        }
+    }
+
+    @Override
+    public void onConnectionFailure(final IOException ex) {
+        onAsyncException(ex);
+        if (!closing.get() && !closed.get()) {
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    providerFailed(ex);
+                    if (provider != null) {
+                        try {
+                            provider.close();
+                        } catch (Throwable error) {
+                            LOG.debug("Error while closing failed Provider: {}", error.getMessage());
+                        }
+                    }
+
+                    try {
+                        shutdown();
+                    } catch (JMSException e) {
+                        LOG.warn("Exception during connection cleanup, " + e, e);
+                    }
+
+                    for (JmsConnectionListener listener : connectionListeners) {
+                        listener.onConnectionFailure(ex);
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Handles any asynchronous errors that occur from the JMS framework classes.
+     *
+     * If any listeners are registered they will be notified of the error from a thread
+     * in the Connection's Executor service.
+     *
+     * @param error
+     *        The exception that triggered this error.
+     */
+    public void onAsyncException(Throwable error) {
+        if (!closed.get() && !closing.get()) {
+            if (this.exceptionListener != null) {
+
+                if (!(error instanceof JMSException)) {
+                    error = JmsExceptionSupport.create(error);
+                }
+                final JMSException jmsError = (JMSException)error;
+
+                executor.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        JmsConnection.this.exceptionListener.onException(jmsError);
+                    }
+                });
+            } else {
+                LOG.debug("Async exception with no exception listener: " + error, error);
+            }
+        }
+    }
+
+    protected void providerFailed(IOException error) {
+        failed.set(true);
+        if (firstFailureError == null) {
+            firstFailureError = error;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
new file mode 100644
index 0000000..1333a5e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionFactory.java
@@ -0,0 +1,664 @@
+/**
+ * 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.jms;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.QueueConnection;
+import javax.jms.QueueConnectionFactory;
+import javax.jms.TopicConnection;
+import javax.jms.TopicConnectionFactory;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.jndi.JNDIStorable;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFactory;
+import org.apache.qpid.jms.util.IdGenerator;
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.jms.util.URISupport;
+import org.apache.qpid.jms.util.URISupport.CompositeData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JMS ConnectionFactory Implementation.
+ */
+public class JmsConnectionFactory extends JNDIStorable implements ConnectionFactory, QueueConnectionFactory, TopicConnectionFactory {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsConnectionFactory.class);
+
+    private URI brokerURI;
+    private URI localURI;
+    private String username;
+    private String password;
+    private boolean forceAsyncSend;
+    private boolean alwaysSyncSend;
+    private boolean sendAcksAsync;
+    private boolean omitHost;
+    private boolean messagePrioritySupported = true;
+    private String queuePrefix = "queue://";
+    private String topicPrefix = "topic://";
+    private String tempQueuePrefix = "temp-queue://";
+    private String tempTopicPrefix = "temp-topic://";
+    private long sendTimeout = JmsConnectionInfo.DEFAULT_SEND_TIMEOUT;
+    private long requestTimeout = JmsConnectionInfo.DEFAULT_REQUEST_TIMEOUT;
+    private long closeTimeout = JmsConnectionInfo.DEFAULT_CLOSE_TIMEOUT;
+    private long connectTimeout = JmsConnectionInfo.DEFAULT_CONNECT_TIMEOUT;
+    private boolean watchRemoteDestinations = true;
+    private IdGenerator clientIdGenerator;
+    private String clientIDPrefix;
+    private IdGenerator connectionIdGenerator;
+    private String connectionIDPrefix;
+    private ExceptionListener exceptionListener;
+
+    private JmsPrefetchPolicy prefetchPolicy = new JmsPrefetchPolicy();
+
+    public JmsConnectionFactory() {
+    }
+
+    public JmsConnectionFactory(String username, String password) {
+        setUsername(username);
+        setPassword(password);
+    }
+
+    public JmsConnectionFactory(String brokerURI) {
+        this(createURI(brokerURI));
+    }
+
+    public JmsConnectionFactory(URI brokerURI) {
+        setBrokerURI(brokerURI.toString());
+    }
+
+    public JmsConnectionFactory(String userName, String password, URI brokerURI) {
+        setUsername(userName);
+        setPassword(password);
+        setBrokerURI(brokerURI.toString());
+    }
+
+    public JmsConnectionFactory(String userName, String password, String brokerURI) {
+        setUsername(userName);
+        setPassword(password);
+        setBrokerURI(brokerURI);
+    }
+
+    /**
+     * Set properties
+     *
+     * @param props
+     */
+    public void setProperties(Properties props) {
+        Map<String, String> map = new HashMap<String, String>();
+        for (Map.Entry<Object, Object> entry : props.entrySet()) {
+            map.put(entry.getKey().toString(), entry.getValue().toString());
+        }
+        setProperties(map);
+    }
+
+    @Override
+    public void setProperties(Map<String, String> map) {
+        buildFromProperties(map);
+    }
+
+    /**
+     * @param map
+     */
+    @Override
+    protected void buildFromProperties(Map<String, String> map) {
+        PropertyUtil.setProperties(this, map);
+    }
+
+    /**
+     * @param map
+     */
+    @Override
+    protected void populateProperties(Map<String, String> map) {
+        try {
+            Map<String, String> result = PropertyUtil.getProperties(this);
+            map.putAll(result);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @return a TopicConnection
+     * @throws JMSException
+     * @see javax.jms.TopicConnectionFactory#createTopicConnection()
+     */
+    @Override
+    public TopicConnection createTopicConnection() throws JMSException {
+        return createTopicConnection(getUsername(), getPassword());
+    }
+
+    /**
+     * @param userName
+     * @param password
+     * @return a TopicConnection
+     * @throws JMSException
+     * @see javax.jms.TopicConnectionFactory#createTopicConnection(java.lang.String,
+     *      java.lang.String)
+     */
+    @Override
+    public TopicConnection createTopicConnection(String username, String password) throws JMSException {
+        try {
+            String connectionId = getConnectionIdGenerator().generateId();
+            Provider provider = createProvider(brokerURI);
+            JmsTopicConnection result = new JmsTopicConnection(connectionId, provider, getClientIdGenerator());
+            return configureConnection(result, username, password);
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    /**
+     * @return a Connection
+     * @throws JMSException
+     * @see javax.jms.ConnectionFactory#createConnection()
+     */
+    @Override
+    public Connection createConnection() throws JMSException {
+        return createConnection(getUsername(), getPassword());
+    }
+
+    /**
+     * @param userName
+     * @param password
+     * @return Connection
+     * @throws JMSException
+     * @see javax.jms.ConnectionFactory#createConnection(java.lang.String, java.lang.String)
+     */
+    @Override
+    public Connection createConnection(String username, String password) throws JMSException {
+        try {
+            String connectionId = getConnectionIdGenerator().generateId();
+            Provider provider = createProvider(brokerURI);
+            JmsConnection result = new JmsConnection(connectionId, provider, getClientIdGenerator());
+            return configureConnection(result, username, password);
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    /**
+     * @return a QueueConnection
+     * @throws JMSException
+     * @see javax.jms.QueueConnectionFactory#createQueueConnection()
+     */
+    @Override
+    public QueueConnection createQueueConnection() throws JMSException {
+        return createQueueConnection(getUsername(), getPassword());
+    }
+
+    /**
+     * @param userName
+     * @param password
+     * @return a QueueConnection
+     * @throws JMSException
+     * @see javax.jms.QueueConnectionFactory#createQueueConnection(java.lang.String,
+     *      java.lang.String)
+     */
+    @Override
+    public QueueConnection createQueueConnection(String username, String password) throws JMSException {
+        try {
+            String connectionId = getConnectionIdGenerator().generateId();
+            Provider provider = createProvider(brokerURI);
+            JmsQueueConnection result = new JmsQueueConnection(connectionId, provider, getClientIdGenerator());
+            return configureConnection(result, username, password);
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    protected <T extends JmsConnection> T configureConnection(T connection, String username, String password) throws JMSException {
+        try {
+            PropertyUtil.setProperties(connection, PropertyUtil.getProperties(this));
+            connection.setExceptionListener(exceptionListener);
+            connection.setUsername(username);
+            connection.setPassword(password);
+            connection.setBrokerURI(brokerURI);
+            return connection;
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    protected Provider createProvider(URI brokerURI) throws Exception {
+        Provider result = null;
+
+        try {
+            result = ProviderFactory.createAsync(brokerURI);
+        } catch (Exception ex) {
+            LOG.error("Failed to create JMS Provider instance for: {}", brokerURI.getScheme());
+            LOG.trace("Error: ", ex);
+            throw ex;
+        }
+
+        return result;
+    }
+
+    protected static URI createURI(String name) {
+        if (name != null && name.trim().isEmpty() == false) {
+            try {
+                return new URI(name);
+            } catch (URISyntaxException e) {
+                throw (IllegalArgumentException) new IllegalArgumentException("Invalid broker URI: " + name).initCause(e);
+            }
+        }
+        return null;
+    }
+
+    protected synchronized IdGenerator getConnectionIdGenerator() {
+        if (connectionIdGenerator == null) {
+            if (connectionIDPrefix != null) {
+                connectionIdGenerator = new IdGenerator(connectionIDPrefix);
+            } else {
+                connectionIdGenerator = new IdGenerator();
+            }
+        }
+        return connectionIdGenerator;
+    }
+
+    protected void setConnectionIdGenerator(IdGenerator connectionIdGenerator) {
+        this.connectionIdGenerator = connectionIdGenerator;
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Property getters and setters
+    //////////////////////////////////////////////////////////////////////////
+
+    /**
+     * @return the brokerURI
+     */
+    public String getBrokerURI() {
+        return this.brokerURI != null ? this.brokerURI.toString() : "";
+    }
+
+    /**
+     * @param brokerURI
+     *        the brokerURI to set
+     */
+    public void setBrokerURI(String brokerURI) {
+        if (brokerURI == null) {
+            throw new IllegalArgumentException("brokerURI cannot be null");
+        }
+        this.brokerURI = createURI(brokerURI);
+
+        try {
+            if (this.brokerURI.getQuery() != null) {
+                Map<String, String> map = PropertyUtil.parseQuery(this.brokerURI.getQuery());
+                Map<String, String> jmsOptionsMap = PropertyUtil.filterProperties(map, "jms.");
+
+                if (!PropertyUtil.setProperties(this, jmsOptionsMap)) {
+                    String msg = ""
+                        + " Not all jms options could be set on the ConnectionFactory."
+                        + " Check the options are spelled correctly."
+                        + " Given parameters=[" + jmsOptionsMap + "]."
+                        + " This connection factory cannot be started.";
+                    throw new IllegalArgumentException(msg);
+                } else {
+                    this.brokerURI = PropertyUtil.replaceQuery(this.brokerURI, map);
+                }
+            } else if (URISupport.isCompositeURI(this.brokerURI)) {
+                CompositeData data = URISupport.parseComposite(this.brokerURI);
+                Map<String, String> jmsOptionsMap = PropertyUtil.filterProperties(data.getParameters(), "jms.");
+                if (!PropertyUtil.setProperties(this, jmsOptionsMap)) {
+                    String msg = ""
+                        + " Not all jms options could be set on the ConnectionFactory."
+                        + " Check the options are spelled correctly."
+                        + " Given parameters=[" + jmsOptionsMap + "]."
+                        + " This connection factory cannot be started.";
+                    throw new IllegalArgumentException(msg);
+                } else {
+                    this.brokerURI = data.toURI();
+                }
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+    /**
+     * @return the localURI
+     */
+    public String getLocalURI() {
+        return this.localURI != null ? this.localURI.toString() : "";
+    }
+
+    /**
+     * @param localURI
+     *        the localURI to set
+     */
+    public void setLocalURI(String localURI) {
+        this.localURI = createURI(localURI);
+    }
+
+    /**
+     * @return the username
+     */
+    public String getUsername() {
+        return this.username;
+    }
+
+    /**
+     * @param username
+     *        the username to set
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * @return the password
+     */
+    public String getPassword() {
+        return this.password;
+    }
+
+    /**
+     * @param password
+     *        the password to set
+     */
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public boolean isForceAsyncSend() {
+        return forceAsyncSend;
+    }
+
+    public void setForceAsyncSend(boolean forceAsyncSend) {
+        this.forceAsyncSend = forceAsyncSend;
+    }
+
+    public boolean isOmitHost() {
+        return omitHost;
+    }
+
+    public void setOmitHost(boolean omitHost) {
+        this.omitHost = omitHost;
+    }
+
+    /**
+     * @return the messagePrioritySupported configuration option.
+     */
+    public boolean isMessagePrioritySupported() {
+        return this.messagePrioritySupported;
+    }
+
+    /**
+     * Enables message priority support in MessageConsumer instances.  This results
+     * in all prefetched messages being dispatched in priority order.
+     *
+     * @param messagePrioritySupported the messagePrioritySupported to set
+     */
+    public void setMessagePrioritySupported(boolean messagePrioritySupported) {
+        this.messagePrioritySupported = messagePrioritySupported;
+    }
+
+    /**
+     * Returns the prefix applied to Queues that are created by the client.
+     *
+     * @return the currently configured Queue prefix.
+     */
+    public String getQueuePrefix() {
+        return queuePrefix;
+    }
+
+    public void setQueuePrefix(String queuePrefix) {
+        this.queuePrefix = queuePrefix;
+    }
+
+    /**
+     * Returns the prefix applied to Temporary Queues that are created by the client.
+     *
+     * @return the currently configured Temporary Queue prefix.
+     */
+    public String getTempQueuePrefix() {
+        return tempQueuePrefix;
+    }
+
+    public void setTempQueuePrefix(String tempQueuePrefix) {
+        this.tempQueuePrefix = tempQueuePrefix;
+    }
+
+    /**
+     * Returns the prefix applied to Temporary Topics that are created by the client.
+     *
+     * @return the currently configured Temporary Topic prefix.
+     */
+    public String getTempTopicPrefix() {
+        return tempTopicPrefix;
+    }
+
+    public void setTempTopicPrefix(String tempTopicPrefix) {
+        this.tempTopicPrefix = tempTopicPrefix;
+    }
+
+    /**
+     * Returns the prefix applied to Topics that are created by the client.
+     *
+     * @return the currently configured Topic prefix.
+     */
+    public String getTopicPrefix() {
+        return topicPrefix;
+    }
+
+    public void setTopicPrefix(String topicPrefix) {
+        this.topicPrefix = topicPrefix;
+    }
+
+    /**
+     * Gets the currently set close timeout.
+     *
+     * @return the currently set close timeout.
+     */
+    public long getCloseTimeout() {
+        return closeTimeout;
+    }
+
+    /**
+     * Sets the close timeout used to control how long a Connection close will wait for
+     * clean shutdown of the connection before giving up.  A negative value means wait
+     * forever.
+     *
+     * Care should be taken in that a very short close timeout can cause the client to
+     * not cleanly shutdown the connection and it's resources.
+     *
+     * @param closeTimeout
+     *        time in milliseconds to wait for a clean connection close.
+     */
+    public void setCloseTimeout(long closeTimeout) {
+        this.closeTimeout = closeTimeout;
+    }
+
+    /**
+     * Returns the currently configured wire level connect timeout.
+     *
+     * @return the currently configured wire level connect timeout.
+     */
+    public long getConnectTimeout() {
+        return this.connectTimeout;
+    }
+
+    /**
+     * Sets the timeout value used to control how long a client will wait for a successful
+     * connection to the remote peer to be established before considering the attempt to
+     * have failed.  This value does not control socket level connection timeout but rather
+     * connection handshake at the wire level, to control the socket level timeouts use the
+     * standard socket options configuration values.
+     *
+     * @param connectTimeout
+     *        the time in milliseconds to wait for the protocol connection handshake to complete.
+     */
+    public void setConnectTimeout(long connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public long getSendTimeout() {
+        return sendTimeout;
+    }
+
+    public void setSendTimeout(long sendTimeout) {
+        this.sendTimeout = sendTimeout;
+    }
+
+    public long getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    public void setRequestTimeout(long requestTimeout) {
+        this.requestTimeout = requestTimeout;
+    }
+
+    public JmsPrefetchPolicy getPrefetchPolicy() {
+        return prefetchPolicy;
+    }
+
+    public void setPrefetchPolicy(JmsPrefetchPolicy prefetchPolicy) {
+        this.prefetchPolicy = prefetchPolicy;
+    }
+
+    public String getClientIDPrefix() {
+        return clientIDPrefix;
+    }
+
+    /**
+     * Sets the prefix used by auto-generated JMS Client ID values which are used if the JMS
+     * client does not explicitly specify on.
+     *
+     * @param clientIDPrefix
+     */
+    public void setClientIDPrefix(String clientIDPrefix) {
+        this.clientIDPrefix = clientIDPrefix;
+    }
+
+    protected synchronized IdGenerator getClientIdGenerator() {
+        if (clientIdGenerator == null) {
+            if (clientIDPrefix != null) {
+                clientIdGenerator = new IdGenerator(clientIDPrefix);
+            } else {
+                clientIdGenerator = new IdGenerator();
+            }
+        }
+        return clientIdGenerator;
+    }
+
+    protected void setClientIdGenerator(IdGenerator clientIdGenerator) {
+        this.clientIdGenerator = clientIdGenerator;
+    }
+
+    /**
+     * Sets the prefix used by connection id generator.
+     *
+     * @param connectionIDPrefix
+     *        The string prefix used on all connection Id's created by this factory.
+     */
+    public void setConnectionIDPrefix(String connectionIDPrefix) {
+        this.connectionIDPrefix = connectionIDPrefix;
+    }
+
+    /**
+     * Gets the currently configured JMS ExceptionListener that will be set on all
+     * new Connection objects created from this factory.
+     *
+     * @return the currently configured JMS ExceptionListener.
+     */
+    public ExceptionListener getExceptionListener() {
+        return exceptionListener;
+    }
+
+    /**
+     * Sets the JMS ExceptionListener that will be set on all new Connection objects
+     * created from this factory.
+     *
+     * @param exceptionListener
+     *        the JMS ExceptionListenenr to apply to new Connection's or null to clear.
+     */
+    public void setExceptionListener(ExceptionListener exceptionListener) {
+        this.exceptionListener = exceptionListener;
+    }
+
+    /**
+     * Indicates if the Connection's created from this factory will watch for updates
+     * from the remote peer informing of temporary destination creation and destruction.
+     *
+     * @return true if destination monitoring is enabled.
+     */
+    public boolean isWatchRemoteDestinations() {
+        return watchRemoteDestinations;
+    }
+
+    /**
+     * Enable or disable monitoring of remote temporary destination life-cycles.
+     *
+     * @param watchRemoteDestinations
+     *        true if connection instances should monitor remote destination life-cycles.
+     */
+    public void setWatchRemoteDestinations(boolean watchRemoteDestinations) {
+        this.watchRemoteDestinations = watchRemoteDestinations;
+    }
+
+    /**
+     * Returns true if the client should always send messages using a synchronous
+     * send operation regardless of persistence mode, or inside a transaction.
+     *
+     * @return true if sends should always be done synchronously.
+     */
+    public boolean isAlwaysSyncSend() {
+        return alwaysSyncSend;
+    }
+
+    /**
+     * Configures whether or not the client will always send messages synchronously or not
+     * regardless of other factors that might result in an asynchronous send.
+     *
+     * @param alwaysSyncSend
+     *        if true sends are always done synchronously.
+     */
+    public void setAlwaysSyncSend(boolean alwaysSyncSend) {
+        this.alwaysSyncSend = alwaysSyncSend;
+    }
+
+    /**
+     * @return true if consumer acknowledgments are sent asynchronously or not.
+     */
+    public boolean isSendAcksAsync() {
+        return sendAcksAsync;
+    }
+
+    /**
+     * Should the message acknowledgments from a consumer be sent synchronously or
+     * asynchronously.  Sending the acknowledgments asynchronously can increase the
+     * performance of a consumer but opens up the possibility of a missed message
+     * acknowledge should the connection be unstable.
+     *
+     * @param sendAcksAsync
+     *        true to have the client send all message acknowledgments asynchronously.
+     */
+    public void setSendAcksAsync(boolean sendAcksAsync) {
+        this.sendAcksAsync = sendAcksAsync;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionListener.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionListener.java
new file mode 100644
index 0000000..2439760
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionListener.java
@@ -0,0 +1,62 @@
+/**
+ * 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.jms;
+
+import java.net.URI;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Providers an interface for client's to listener to events related to
+ * an JmsConnection.
+ */
+public interface JmsConnectionListener {
+
+    /**
+     * Called when an unrecoverable error occurs and the Connection must be closed.
+     *
+     * @param error
+     *        The error that triggered the failure.
+     */
+    void onConnectionFailure(Throwable error);
+
+    /**
+     * Called when the Connection to the remote peer is lost.
+     *
+     * @param remoteURI
+     *        The URI of the Broker previously connected to.
+     */
+    void onConnectionInterrupted(URI remoteURI);
+
+    /**
+     * Called when normal communication has been restored to a remote peer.
+     *
+     * @param remoteURI
+     *        The URI of the Broker that this client is now connected to.
+     */
+    void onConnectionRestored(URI remoteURI);
+
+    /**
+     * Called when a Connection is notified that a new Message has arrived for
+     * one of it's currently active subscriptions.
+     *
+     * @param envelope
+     *        The envelope that contains the incoming message and it's delivery information.
+     */
+    void onMessage(JmsInboundMessageDispatch envelope);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionMetaData.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionMetaData.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionMetaData.java
new file mode 100644
index 0000000..f674320
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsConnectionMetaData.java
@@ -0,0 +1,164 @@
+/**
+ * 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.jms;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.jms.ConnectionMetaData;
+
+/**
+ * A <CODE>ConnectionMetaData</CODE> object provides information describing
+ * the <CODE>Connection</CODE> object.
+ */
+public final class JmsConnectionMetaData implements ConnectionMetaData {
+
+    public static final String PROVIDER_VERSION;
+    public static final int PROVIDER_MAJOR_VERSION;
+    public static final int PROVIDER_MINOR_VERSION;
+
+    public static final JmsConnectionMetaData INSTANCE = new JmsConnectionMetaData();
+
+    static {
+        String version = null;
+        int major = 0;
+        int minor = 0;
+        try {
+            Package p = Package.getPackage("org.apache.qpid.jms");
+            if (p != null) {
+                version = p.getImplementationVersion();
+                Pattern pattern = Pattern.compile("(\\d+)\\.(\\d+).*");
+                Matcher m = pattern.matcher(version);
+                if (m.matches()) {
+                    major = Integer.parseInt(m.group(1));
+                    minor = Integer.parseInt(m.group(2));
+                }
+            }
+        } catch (Throwable e) {
+            InputStream in = null;
+            if ((in = JmsConnectionMetaData.class.getResourceAsStream("/org/apache/qpid/jms/version.txt")) != null) {
+                try {
+                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+                    version = reader.readLine();
+                    Pattern pattern = Pattern.compile("(\\d+)\\.(\\d+).*");
+                    Matcher m = pattern.matcher(version);
+                    if (m.matches()) {
+                        major = Integer.parseInt(m.group(1));
+                        minor = Integer.parseInt(m.group(2));
+                    }
+                    reader.close();
+                } catch(Throwable err) {
+                }
+            }
+        }
+        PROVIDER_VERSION = version;
+        PROVIDER_MAJOR_VERSION = major;
+        PROVIDER_MINOR_VERSION = minor;
+    }
+
+    private JmsConnectionMetaData() {}
+
+    /**
+     * Gets the JMS API version.
+     *
+     * @return the JMS API version
+     */
+    @Override
+    public String getJMSVersion() {
+        return "1.1";
+    }
+
+    /**
+     * Gets the JMS major version number.
+     *
+     * @return the JMS API major version number
+     */
+    @Override
+    public int getJMSMajorVersion() {
+        return 1;
+    }
+
+    /**
+     * Gets the JMS minor version number.
+     *
+     * @return the JMS API minor version number
+     */
+    @Override
+    public int getJMSMinorVersion() {
+        return 1;
+    }
+
+    /**
+     * Gets the JMS provider name.
+     *
+     * @return the JMS provider name
+     */
+    @Override
+    public String getJMSProviderName() {
+        return "QpidJMS";
+    }
+
+    /**
+     * Gets the JMS provider version.
+     *
+     * @return the JMS provider version
+     */
+    @Override
+    public String getProviderVersion() {
+        return PROVIDER_VERSION;
+    }
+
+    /**
+     * Gets the JMS provider major version number.
+     *
+     * @return the JMS provider major version number
+     */
+    @Override
+    public int getProviderMajorVersion() {
+        return PROVIDER_MAJOR_VERSION;
+    }
+
+    /**
+     * Gets the JMS provider minor version number.
+     *
+     * @return the JMS provider minor version number
+     */
+    @Override
+    public int getProviderMinorVersion() {
+        return PROVIDER_MINOR_VERSION;
+    }
+
+    /**
+     * Gets an enumeration of the JMSX property names.
+     *
+     * @return an Enumeration of JMSX property names
+     */
+    @Override
+    public Enumeration<String> getJMSXPropertyNames() {
+        Vector<String> jmxProperties = new Vector<String>();
+        jmxProperties.add("JMSXUserID");
+        jmxProperties.add("JMSXGroupID");
+        jmxProperties.add("JMSXGroupSeq");
+        jmxProperties.add("JMSXDeliveryCount");
+        return jmxProperties.elements();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDestination.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDestination.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDestination.java
new file mode 100644
index 0000000..a86e0f7
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDestination.java
@@ -0,0 +1,189 @@
+/**
+ * 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.jms;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.jndi.JNDIStorable;
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.meta.JmsResourceVistor;
+
+/**
+ * Jms Destination
+ */
+public abstract class JmsDestination extends JNDIStorable implements JmsResource, Externalizable, javax.jms.Destination, Comparable<JmsDestination> {
+
+    protected transient String name;
+    protected transient boolean topic;
+    protected transient boolean temporary;
+    protected transient int hashValue;
+    protected transient JmsConnection connection;
+
+    protected JmsDestination(String name, boolean topic, boolean temporary) {
+        this.name = name;
+        this.topic = topic;
+        this.temporary = temporary;
+    }
+
+    public abstract JmsDestination copy();
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * @return name of destination
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * @return the topic
+     */
+    public boolean isTopic() {
+        return this.topic;
+    }
+
+    /**
+     * @return the temporary
+     */
+    public boolean isTemporary() {
+        return this.temporary;
+    }
+
+    /**
+     * @return true if a Topic
+     */
+    public boolean isQueue() {
+        return !this.topic;
+    }
+
+    /**
+     * @param props
+     */
+    @Override
+    protected void buildFromProperties(Map<String, String> props) {
+        setName(getProperty(props, "name", ""));
+        Boolean bool = Boolean.valueOf(getProperty(props, "topic", Boolean.TRUE.toString()));
+        this.topic = bool.booleanValue();
+        bool = Boolean.valueOf(getProperty(props, "temporary", Boolean.FALSE.toString()));
+        this.temporary = bool.booleanValue();
+    }
+
+    /**
+     * @param props
+     */
+    @Override
+    protected void populateProperties(Map<String, String> props) {
+        props.put("name", getName());
+        props.put("topic", Boolean.toString(isTopic()));
+        props.put("temporary", Boolean.toString(isTemporary()));
+    }
+
+    /**
+     * @param other
+     *        the Object to be compared.
+     * @return a negative integer, zero, or a positive integer as this object is
+     *         less than, equal to, or greater than the specified object.
+     * @see java.lang.Comparable#compareTo(java.lang.Object)
+     */
+    @Override
+    public int compareTo(JmsDestination other) {
+        if (other != null) {
+            if (this == other) {
+                return 0;
+            }
+            if (isTemporary() == other.isTemporary()) {
+                return getName().compareTo(other.getName());
+            }
+            return -1;
+        }
+        return -1;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        JmsDestination d = (JmsDestination) o;
+        return getName().equals(d.getName());
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashValue == 0) {
+            hashValue = getName().hashCode();
+        }
+        return hashValue;
+    }
+
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeUTF(getName());
+        out.writeBoolean(isTopic());
+        out.writeBoolean(isTemporary());
+    }
+
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        setName(in.readUTF());
+        this.topic = in.readBoolean();
+        this.temporary = in.readBoolean();
+    }
+
+    void setConnection(JmsConnection connection) {
+        this.connection = connection;
+    }
+
+    JmsConnection getConnection() {
+        return this.connection;
+    }
+
+    /**
+     * Attempts to delete the destination if there is an assigned Connection object.
+     *
+     * @throws JMSException if an error occurs or the provider doesn't support
+     *         delete of destinations from the client.
+     */
+    protected void tryDelete() throws JMSException {
+        if (connection != null) {
+            connection.deleteDestination(this);
+        }
+    }
+
+    @Override
+    public void visit(JmsResourceVistor visitor) throws Exception {
+        visitor.processDestination(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDurableTopicSubscriber.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDurableTopicSubscriber.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDurableTopicSubscriber.java
new file mode 100644
index 0000000..b7ae1b9
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsDurableTopicSubscriber.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.meta.JmsConsumerId;
+
+/**
+ * Implementation of a TopicSubscriber that is Durable
+ */
+public class JmsDurableTopicSubscriber extends JmsTopicSubscriber {
+
+    /**
+     * Creates a durable TopicSubscriber
+     *
+     * @param id
+     * @param s
+     * @param destination
+     * @param name
+     * @param noLocal
+     * @param selector
+     * @throws JMSException
+     */
+    public JmsDurableTopicSubscriber(JmsConsumerId id, JmsSession s, JmsDestination destination, String name, boolean noLocal, String selector) throws JMSException {
+        super(id, s, destination, name, noLocal, selector);
+    }
+
+    @Override
+    public boolean isDurableSubscription() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsLocalTransactionContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsLocalTransactionContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsLocalTransactionContext.java
new file mode 100644
index 0000000..c9395ba
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsLocalTransactionContext.java
@@ -0,0 +1,216 @@
+/**
+ * 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.jms;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.meta.JmsTransactionId;
+import org.apache.qpid.jms.meta.JmsTransactionInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages the details of a Session operating inside of a local JMS transaction.
+ */
+public class JmsLocalTransactionContext {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsLocalTransactionContext.class);
+
+    private List<JmsTxSynchronization> synchronizations;
+    private final JmsSession session;
+    private final JmsConnection connection;
+    private JmsTransactionId transactionId;
+    private JmsTransactionListener listener;
+
+    public JmsLocalTransactionContext(JmsSession session) {
+        this.session = session;
+        this.connection = session.getConnection();
+    }
+
+    /**
+     * Adds the given Transaction synchronization to the current list.
+     *
+     * @param synchronization
+     *        the transaction synchronization to add.
+     */
+    public void addSynchronization(JmsTxSynchronization s) {
+        if (synchronizations == null) {
+            synchronizations = new ArrayList<JmsTxSynchronization>(10);
+        }
+        synchronizations.add(s);
+    }
+
+    /**
+     * Clears the current Transacted state.  This is usually done when the client
+     * detects that a failover has occurred and needs to create a new Transaction
+     * for a Session that was previously enlisted in a transaction.
+     */
+    public void clear() {
+        this.transactionId = null;
+        this.synchronizations = null;
+    }
+
+    /**
+     * Start a local transaction.
+     *
+     * @throws javax.jms.JMSException on internal error
+     */
+    public void begin() throws JMSException {
+        if (transactionId == null) {
+            synchronizations = null;
+
+            transactionId = connection.getNextTransactionId();
+            JmsTransactionInfo transaction = new JmsTransactionInfo(session.getSessionId(), transactionId);
+            connection.createResource(transaction);
+
+            if (listener != null) {
+                listener.onTransactionStarted();
+            }
+
+            LOG.debug("Begin: {}", transactionId);
+        }
+    }
+
+    /**
+     * Rolls back any work done in this transaction and releases any locks
+     * currently held.
+     *
+     * @throws JMSException
+     *         if the JMS provider fails to roll back the transaction due to some internal error.
+     */
+    public void rollback() throws JMSException {
+        if (transactionId != null) {
+            LOG.debug("Rollback: {} syncCount: {}", transactionId,
+                      (synchronizations != null ? synchronizations.size() : 0));
+
+            transactionId = null;
+            connection.rollback(session.getSessionId());
+
+            if (listener != null) {
+                listener.onTransactionRolledBack();
+            }
+        }
+
+        afterRollback();
+    }
+
+    /**
+     * Commits all work done in this transaction and releases any locks
+     * currently held.
+     *
+     * @throws JMSException
+     *         if the JMS provider fails to roll back the transaction due to some internal error.
+     */
+    public void commit() throws JMSException {
+        if (transactionId != null) {
+            LOG.debug("Commit: {} syncCount: {}", transactionId,
+                      (synchronizations != null ? synchronizations.size() : 0));
+
+            JmsTransactionId oldTransactionId = this.transactionId;
+            transactionId = null;
+            try {
+                connection.commit(session.getSessionId());
+                if (listener != null) {
+                    listener.onTransactionCommitted();
+                }
+                afterCommit();
+            } catch (JMSException cause) {
+                LOG.info("Commit failed for transaction: {}", oldTransactionId);
+                if (listener != null) {
+                    listener.onTransactionRolledBack();
+                }
+                afterRollback();
+                throw cause;
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "JmsLocalTransactionContext{transactionId=" + transactionId + "}";
+    }
+
+    //------------- Getters and Setters --------------------------------------//
+
+    public JmsTransactionId getTransactionId() {
+        return this.transactionId;
+    }
+
+    public JmsTransactionListener getListener() {
+        return listener;
+    }
+
+    public void setListener(JmsTransactionListener listener) {
+        this.listener = listener;
+    }
+
+    public boolean isInTransaction() {
+        return this.transactionId != null;
+    }
+
+    //------------- Implementation methods -----------------------------------//
+
+    private void afterRollback() throws JMSException {
+        if (synchronizations == null) {
+            return;
+        }
+
+        Throwable firstException = null;
+        int size = synchronizations.size();
+        for (int i = 0; i < size; i++) {
+            try {
+                synchronizations.get(i).afterRollback();
+            } catch (Throwable thrown) {
+                LOG.debug("Exception from afterRollback on " + synchronizations.get(i), thrown);
+                if (firstException == null) {
+                    firstException = thrown;
+                }
+            }
+        }
+        synchronizations = null;
+        if (firstException != null) {
+            throw JmsExceptionSupport.create(firstException);
+        }
+    }
+
+    private void afterCommit() throws JMSException {
+        if (synchronizations == null) {
+            return;
+        }
+
+        Throwable firstException = null;
+        int size = synchronizations.size();
+        for (int i = 0; i < size; i++) {
+            try {
+                synchronizations.get(i).afterCommit();
+            } catch (Throwable thrown) {
+                LOG.debug("Exception from afterCommit on " + synchronizations.get(i), thrown);
+                if (firstException == null) {
+                    firstException = thrown;
+                }
+            }
+        }
+        synchronizations = null;
+        if (firstException != null) {
+            throw JmsExceptionSupport.create(firstException);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableConsumer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableConsumer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableConsumer.java
new file mode 100644
index 0000000..31f53c6
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableConsumer.java
@@ -0,0 +1,45 @@
+/**
+ * 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.jms;
+
+import javax.jms.MessageConsumer;
+
+/**
+ * Marker interface used for MessageConsumer instances that support sending
+ * a notification event when a message has arrived when the consumer is not
+ * in asynchronous dispatch mode.
+ */
+public interface JmsMessageAvailableConsumer {
+
+    /**
+     * Sets the listener used to notify synchronous consumers that there is a message
+     * available so that the {@link MessageConsumer#receiveNoWait()} can be called.
+     *
+     * @param availableListener
+     *        the JmsMessageAvailableListener instance to signal.
+     */
+    void setAvailableListener(JmsMessageAvailableListener availableListener);
+
+    /**
+     * Gets the listener used to notify synchronous consumers that there is a message
+     * available so that the {@link MessageConsumer#receiveNoWait()} can be called.
+     *
+     * @return the currently configured message available listener instance.
+     */
+    JmsMessageAvailableListener getAvailableListener();
+
+}


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


[18/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactory.java
new file mode 100644
index 0000000..b1d0782
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProviderFactory.java
@@ -0,0 +1,57 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFactory;
+import org.apache.qpid.jms.util.PropertyUtil;
+
+/**
+ * Factory for creating the AMQP provider.
+ */
+public class AmqpProviderFactory extends ProviderFactory {
+
+    @Override
+    public Provider createAsyncProvider(URI remoteURI) throws Exception {
+
+        Map<String, String> map = PropertyUtil.parseQuery(remoteURI.getQuery());
+        Map<String, String> providerOptions = PropertyUtil.filterProperties(map, "provider.");
+
+        remoteURI = PropertyUtil.replaceQuery(remoteURI, map);
+
+        Provider result = new AmqpProvider(remoteURI);
+
+        if (!PropertyUtil.setProperties(result, providerOptions)) {
+            String msg = ""
+                + " Not all provider options could be set on the AMQP Provider."
+                + " Check the options are spelled correctly."
+                + " Given parameters=[" + providerOptions + "]."
+                + " This provider instance cannot be started.";
+            throw new IllegalArgumentException(msg);
+        }
+
+        return result;
+    }
+
+    @Override
+    public String getName() {
+        return "AMQP";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpQueueBrowser.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpQueueBrowser.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpQueueBrowser.java
new file mode 100644
index 0000000..e23b4c0
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpQueueBrowser.java
@@ -0,0 +1,127 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Queue Browser implementation for AMQP
+ */
+public class AmqpQueueBrowser extends AmqpConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpQueueBrowser.class);
+
+    /**
+     * @param session
+     * @param info
+     */
+    public AmqpQueueBrowser(AmqpSession session, JmsConsumerInfo info) {
+        super(session, info);
+    }
+
+    /**
+     * Starts the QueueBrowser by activating drain mode with the initial credits.
+     */
+    @Override
+    public void start(AsyncResult request) {
+        this.endpoint.flow(info.getPrefetchSize());
+        request.onSuccess();
+    }
+
+    /**
+     * QueueBrowser will attempt to initiate a pull whenever there are no pending Messages.
+     *
+     * We need to initiate a drain to see if there are any messages and if the remote sender
+     * indicates it is drained then we can send end of browse.  We only do this when there
+     * are no pending incoming deliveries and all delivered messages have become settled
+     * in order to give the remote a chance to dispatch more messages once all deliveries
+     * have been settled.
+     *
+     * @param timeout
+     *        ignored in this context.
+     */
+    @Override
+    public void pull(long timeout) {
+        if (!endpoint.getDrain() && endpoint.current() == null && endpoint.getUnsettled() == 0) {
+            LOG.trace("QueueBrowser {} will try to drain remote.", getConsumerId());
+            this.endpoint.drain(info.getPrefetchSize());
+        } else {
+            endpoint.setDrain(false);
+        }
+    }
+
+    @Override
+    public void processFlowUpdates() throws IOException {
+        if (endpoint.getDrain() && endpoint.getCredit() == endpoint.getRemoteCredit()) {
+            JmsInboundMessageDispatch browseDone = new JmsInboundMessageDispatch();
+            browseDone.setConsumerId(getConsumerId());
+            try {
+                deliver(browseDone);
+            } catch (Exception e) {
+                throw IOExceptionSupport.create(e);
+            }
+        } else {
+            endpoint.setDrain(false);
+        }
+
+        super.processFlowUpdates();
+    }
+
+    @Override
+    public void processDeliveryUpdates() throws IOException {
+        if (endpoint.getDrain() && endpoint.current() != null) {
+            LOG.trace("{} incoming delivery, cancel drain.", getConsumerId());
+            endpoint.setDrain(false);
+        }
+
+        super.processDeliveryUpdates();
+
+        if (endpoint.getDrain() && endpoint.getCredit() == endpoint.getRemoteCredit()) {
+            JmsInboundMessageDispatch browseDone = new JmsInboundMessageDispatch();
+            browseDone.setConsumerId(getConsumerId());
+            try {
+                deliver(browseDone);
+            } catch (Exception e) {
+                throw IOExceptionSupport.create(e);
+            }
+        } else {
+            endpoint.setDrain(false);
+        }
+    }
+
+    @Override
+    protected void configureSource(Source source) {
+        if (info.isBrowser()) {
+            source.setDistributionMode(COPY);
+        }
+
+        super.configureSource(source);
+    }
+
+    @Override
+    public boolean isBrowser() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpResource.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpResource.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpResource.java
new file mode 100644
index 0000000..46f8130
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpResource.java
@@ -0,0 +1,130 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+
+import org.apache.qpid.jms.provider.AsyncResult;
+
+/**
+ * AmqpResource specification.
+ *
+ * All AMQP types should implement this interface to allow for control of state
+ * and configuration details.
+ */
+public interface AmqpResource {
+
+    /**
+     * Perform all the work needed to open this resource and store the request
+     * until such time as the remote peer indicates the resource has become active.
+     *
+     * @param request
+     *        The initiating request that triggered this open call.
+     */
+    void open(AsyncResult request);
+
+    /**
+     * @return if the resource has moved to the opened state on the remote.
+     */
+    boolean isOpen();
+
+    /**
+     * @return true if the resource is awaiting the remote end to signal opened.
+     */
+    boolean isAwaitingOpen();
+
+    /**
+     * Called to indicate that this resource is now remotely opened.  Once opened a
+     * resource can start accepting incoming requests.
+     */
+    void opened();
+
+    /**
+     * Perform all work needed to close this resource and store the request
+     * until such time as the remote peer indicates the resource has been closed.
+     *
+     * @param request
+     *        The initiating request that triggered this close call.
+     */
+    void close(AsyncResult request);
+
+    /**
+     * @return if the resource has moved to the closed state on the remote.
+     */
+    boolean isClosed();
+
+    /**
+     * @return true if the resource is awaiting the remote end to signal closed.
+     */
+    boolean isAwaitingClose();
+
+    /**
+     * Called to indicate that this resource is now remotely closed.  Once closed a
+     * resource can not accept any incoming requests.
+     */
+    void closed();
+
+    /**
+     * Sets the failed state for this Resource and triggers a failure signal for
+     * any pending ProduverRequest.
+     */
+    void failed();
+
+    /**
+     * Sets the failed state for this Resource and triggers a failure signal for
+     * any pending ProduverRequest.
+     *
+     * @param cause
+     *        The Exception that triggered the failure.
+     */
+    void failed(Exception cause);
+
+    /**
+     * Called when the Proton Engine signals that the state of the given resource has
+     * changed on the remote side.
+     *
+     * @throws IOException if an error occurs while processing the update.
+     */
+    void processStateChange() throws IOException;
+
+    /**
+     * Called when the Proton Engine signals an Delivery related event has been triggered
+     * for the given endpoint.
+     *
+     * @throws IOException if an error occurs while processing the update.
+     */
+    void processDeliveryUpdates() throws IOException;
+
+    /**
+     * Called when the Proton Engine signals an Flow related event has been triggered
+     * for the given endpoint.
+     *
+     * @throws IOException if an error occurs while processing the update.
+     */
+    void processFlowUpdates() throws IOException;
+
+    /**
+     * @return an Exception derived from the error state of the endpoint's Remote Condition.
+     */
+    Exception getRemoteError();
+
+    /**
+     * @return an Error message derived from the error state of the endpoint's Remote Condition.
+     */
+    String getRemoteErrorMessage();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
new file mode 100644
index 0000000..3416c22
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSaslAuthenticator.java
@@ -0,0 +1,127 @@
+/**
+ * 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.jms.provider.amqp;
+
+import javax.jms.JMSSecurityException;
+import javax.security.sasl.SaslException;
+
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.sasl.Mechanism;
+import org.apache.qpid.jms.sasl.SaslMechanismFinder;
+import org.apache.qpid.proton.engine.Sasl;
+
+/**
+ * Manage the SASL authentication process
+ */
+public class AmqpSaslAuthenticator {
+
+    private final Sasl sasl;
+    private final JmsConnectionInfo info;
+    private Mechanism mechanism;
+
+    /**
+     * Create the authenticator and initialize it.
+     *
+     * @param sasl
+     *        The Proton SASL entry point this class will use to manage the authentication.
+     * @param info
+     *        The Connection information used to provide credentials to the remote peer.
+     */
+    public AmqpSaslAuthenticator(Sasl sasl, JmsConnectionInfo info) {
+        this.sasl = sasl;
+        this.info = info;
+    }
+
+    /**
+     * Process the SASL authentication cycle until such time as an outcome is determine. This
+     * method must be called by the managing entity until the return value is true indicating a
+     * successful authentication or a JMSSecurityException is thrown indicating that the
+     * handshake failed.
+     *
+     * @throws JMSSecurityException
+     */
+    public boolean authenticate() throws JMSSecurityException {
+        switch (sasl.getState()) {
+            case PN_SASL_IDLE:
+                handleSaslInit();
+                break;
+            case PN_SASL_STEP:
+                handleSaslStep();
+                break;
+            case PN_SASL_FAIL:
+                handleSaslFail();
+                break;
+            case PN_SASL_PASS:
+                return true;
+            default:
+        }
+
+        return false;
+    }
+
+    private void handleSaslInit() throws JMSSecurityException {
+        try {
+            String[] remoteMechanisms = sasl.getRemoteMechanisms();
+            if (remoteMechanisms != null && remoteMechanisms.length != 0) {
+                mechanism = SaslMechanismFinder.findMatchingMechanism(remoteMechanisms);
+                if (mechanism != null) {
+                    mechanism.setUsername(info.getUsername());
+                    mechanism.setPassword(info.getPassword());
+                    // TODO - set additional options from URI.
+                    // TODO - set a host value.
+
+                    sasl.setMechanisms(mechanism.getName());
+                    byte[] response = mechanism.getInitialResponse();
+                    if (response != null && response.length != 0) {
+                        sasl.send(response, 0, response.length);
+                    }
+                } else {
+                    // TODO - Better error message.
+                    throw new JMSSecurityException("Could not find a matching SASL mechanism for the remote peer.");
+                }
+            }
+        } catch (SaslException se) {
+            // TODO - Better error message.
+            JMSSecurityException jmsse = new JMSSecurityException("Exception while processing SASL init.");
+            jmsse.setLinkedException(se);
+            jmsse.initCause(se);
+            throw jmsse;
+        }
+    }
+
+    private void handleSaslStep() throws JMSSecurityException {
+        try {
+            if (sasl.pending() != 0) {
+                byte[] challenge = new byte[sasl.pending()];
+                sasl.recv(challenge, 0, challenge.length);
+                byte[] response = mechanism.getChallengeResponse(challenge);
+                sasl.send(response, 0, response.length);
+            }
+        } catch (SaslException se) {
+            // TODO - Better error message.
+            JMSSecurityException jmsse = new JMSSecurityException("Exception while processing SASL step.");
+            jmsse.setLinkedException(se);
+            jmsse.initCause(se);
+            throw jmsse;
+        }
+    }
+
+    private void handleSaslFail() throws JMSSecurityException {
+        // TODO - Better error message.
+        throw new JMSSecurityException("Client failed to authenticate");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSession.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSession.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSession.java
new file mode 100644
index 0000000..44e864a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSession.java
@@ -0,0 +1,281 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.IllegalStateException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.meta.JmsProducerId;
+import org.apache.qpid.jms.meta.JmsProducerInfo;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.meta.JmsTransactionId;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.proton.engine.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AmqpSession extends AbstractAmqpResource<JmsSessionInfo, Session> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpSession.class);
+
+    private final AmqpConnection connection;
+    private final AmqpTransactionContext txContext;
+
+    private final Map<JmsConsumerId, AmqpConsumer> consumers = new HashMap<JmsConsumerId, AmqpConsumer>();
+    private final Map<JmsProducerId, AmqpProducer> producers = new HashMap<JmsProducerId, AmqpProducer>();
+
+    public AmqpSession(AmqpConnection connection, JmsSessionInfo info) {
+        super(info, connection.getProtonConnection().session());
+        this.connection = connection;
+
+        this.info.getSessionId().setProviderHint(this);
+        if (this.info.isTransacted()) {
+            txContext = new AmqpTransactionContext(this);
+        } else {
+            txContext = null;
+        }
+    }
+
+    @Override
+    public void opened() {
+        if (this.txContext != null) {
+            this.txContext.open(openRequest);
+        } else {
+            super.opened();
+        }
+    }
+
+    @Override
+    protected void doOpen() {
+        this.endpoint.setIncomingCapacity(Integer.MAX_VALUE);
+        this.connection.addSession(this);
+    }
+
+    @Override
+    protected void doClose() {
+        this.connection.removeSession(this);
+    }
+
+    /**
+     * Perform an acknowledge of all delivered messages for all consumers active in this
+     * Session.
+     */
+    public void acknowledge() {
+        for (AmqpConsumer consumer : consumers.values()) {
+            consumer.acknowledge();
+        }
+    }
+
+    /**
+     * Perform re-send of all delivered but not yet acknowledged messages for all consumers
+     * active in this Session.
+     *
+     * @throws Exception if an error occurs while performing the recover.
+     */
+    public void recover() throws Exception {
+        for (AmqpConsumer consumer : consumers.values()) {
+            consumer.recover();
+        }
+    }
+
+    public AmqpProducer createProducer(JmsProducerInfo producerInfo) {
+        AmqpProducer producer = null;
+
+        // TODO - There seems to be an issue with Proton not allowing links with a Target
+        //        that has no address.  Otherwise we could just ensure that messages sent
+        //        to these anonymous targets have their 'to' value set to the destination.
+        if (producerInfo.getDestination() != null) {
+            LOG.debug("Creating fixed Producer for: {}", producerInfo.getDestination());
+            producer = new AmqpFixedProducer(this, producerInfo);
+        } else {
+            LOG.debug("Creating an Anonymous Producer: ");
+            producer = new AmqpAnonymousProducer(this, producerInfo);
+        }
+
+        producer.setPresettle(connection.isPresettleProducers());
+
+        return producer;
+    }
+
+    public AmqpProducer getProducer(JmsProducerInfo producerInfo) {
+        return getProducer(producerInfo.getProducerId());
+    }
+
+    public AmqpProducer getProducer(JmsProducerId producerId) {
+        if (producerId.getProviderHint() instanceof AmqpProducer) {
+            return (AmqpProducer) producerId.getProviderHint();
+        }
+        return this.producers.get(producerId);
+    }
+
+    public AmqpConsumer createConsumer(JmsConsumerInfo consumerInfo) {
+        AmqpConsumer result = null;
+
+        if (consumerInfo.isBrowser()) {
+            result = new AmqpQueueBrowser(this, consumerInfo);
+        } else {
+            result = new AmqpConsumer(this, consumerInfo);
+        }
+
+        result.setPresettle(connection.isPresettleConsumers());
+        return result;
+    }
+
+    public AmqpConsumer getConsumer(JmsConsumerInfo consumerInfo) {
+        return getConsumer(consumerInfo.getConsumerId());
+    }
+
+    public AmqpConsumer getConsumer(JmsConsumerId consumerId) {
+        if (consumerId.getProviderHint() instanceof AmqpConsumer) {
+            return (AmqpConsumer) consumerId.getProviderHint();
+        }
+        return this.consumers.get(consumerId);
+    }
+
+    public AmqpTransactionContext getTransactionContext() {
+        return this.txContext;
+    }
+
+    /**
+     * Begins a new Transaction using the given Transaction Id as the identifier.  The AMQP
+     * binary Transaction Id will be stored in the provider hint value of the given transaction.
+     *
+     * @param txId
+     *        The JMS Framework's assigned Transaction Id for the new TX.
+     * @param request
+     *        The request that will be signaled on completion of this operation.
+     *
+     * @throws Exception if an error occurs while performing the operation.
+     */
+    public void begin(JmsTransactionId txId, AsyncResult request) throws Exception {
+        if (!this.info.isTransacted()) {
+            throw new IllegalStateException("Non-transacted Session cannot start a TX.");
+        }
+
+        getTransactionContext().begin(txId, request);
+    }
+
+    /**
+     * Commit the currently running Transaction.
+     *
+     * @param request
+     *        The request that will be signaled on completion of this operation.
+     *
+     * @throws Exception if an error occurs while performing the operation.
+     */
+    public void commit(AsyncResult request) throws Exception {
+        if (!this.info.isTransacted()) {
+            throw new IllegalStateException("Non-transacted Session cannot start a TX.");
+        }
+
+        getTransactionContext().commit(request);
+    }
+
+    /**
+     * Roll back the currently running Transaction
+     *
+     * @param request
+     *        The request that will be signaled on completion of this operation.
+     *
+     * @throws Exception if an error occurs while performing the operation.
+     */
+    public void rollback(AsyncResult request) throws Exception {
+        if (!this.info.isTransacted()) {
+            throw new IllegalStateException("Non-transacted Session cannot start a TX.");
+        }
+
+        getTransactionContext().rollback(request);
+    }
+
+    void addResource(AmqpConsumer consumer) {
+        consumers.put(consumer.getConsumerId(), consumer);
+    }
+
+    void removeResource(AmqpConsumer consumer) {
+        consumers.remove(consumer.getConsumerId());
+    }
+
+    void addResource(AmqpProducer producer) {
+        producers.put(producer.getProducerId(), producer);
+    }
+
+    void removeResource(AmqpProducer producer) {
+        producers.remove(producer.getProducerId());
+    }
+
+    /**
+     * Adds Topic or Queue qualifiers to the destination target.  We don't add qualifiers to
+     * Temporary Topics and Queues since AMQP works a bit differently.
+     *
+     * @param destination
+     *        The destination to Qualify.
+     *
+     * @return the qualified destination name.
+     */
+    public String getQualifiedName(JmsDestination destination) {
+        if (destination == null) {
+            return null;
+        }
+
+        String result = destination.getName();
+
+        if (!destination.isTemporary()) {
+            if (destination.isTopic()) {
+                result = connection.getTopicPrefix() + destination.getName();
+            } else {
+                result = connection.getQueuePrefix() + destination.getName();
+            }
+        }
+
+        return result;
+    }
+
+    public AmqpProvider getProvider() {
+        return this.connection.getProvider();
+    }
+
+    public AmqpConnection getConnection() {
+        return this.connection;
+    }
+
+    public JmsSessionId getSessionId() {
+        return this.info.getSessionId();
+    }
+
+    public Session getProtonSession() {
+        return this.endpoint;
+    }
+
+    boolean isTransacted() {
+        return this.info.isTransacted();
+    }
+
+    boolean isAsyncAck() {
+        return this.info.isSendAcksAsync() || isTransacted();
+    }
+
+    @Override
+    public String toString() {
+        return "AmqpSession { " + getSessionId() + " }";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProvider.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProvider.java
new file mode 100644
index 0000000..af7fe7f
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProvider.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.net.URI;
+import java.util.Map;
+
+import org.apache.qpid.jms.JmsSslContext;
+import org.apache.qpid.jms.transports.SslTransport;
+import org.apache.qpid.jms.transports.Transport;
+
+/**
+ * AmqpProvider extension that enables SSL based transports.
+ */
+public class AmqpSslProvider extends AmqpProvider {
+
+    private final JmsSslContext sslContext;
+
+    public AmqpSslProvider(URI remoteURI) {
+        super(remoteURI);
+        this.sslContext = JmsSslContext.getCurrentSslContext();
+    }
+
+    public AmqpSslProvider(URI remoteURI, Map<String, String> extraOptions) {
+        super(remoteURI, extraOptions);
+        this.sslContext = JmsSslContext.getCurrentSslContext();
+    }
+
+    @Override
+    protected Transport createTransport(URI remoteLocation) {
+        return new SslTransport(this, remoteLocation, sslContext);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProviderFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProviderFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProviderFactory.java
new file mode 100644
index 0000000..7606792
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSslProviderFactory.java
@@ -0,0 +1,32 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.net.URI;
+
+import org.apache.qpid.jms.provider.Provider;
+
+/**
+ * Extends the AmqpProviderFactory to create an SSL based Provider instance.
+ */
+public class AmqpSslProviderFactory extends AmqpProviderFactory {
+
+    @Override
+    public Provider createAsyncProvider(URI remoteURI) throws Exception {
+        return new AmqpSslProvider(remoteURI);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTemporaryDestination.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTemporaryDestination.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTemporaryDestination.java
new file mode 100644
index 0000000..d76e3d7
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTemporaryDestination.java
@@ -0,0 +1,132 @@
+/**
+ * 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.jms.provider.amqp;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.apache.qpid.proton.amqp.messaging.Target;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Sender;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manages a Temporary Destination linked to a given Connection.
+ *
+ * In order to create a temporary destination and keep it active for the life of the connection
+ * we must create a sender with a dynamic target value.  Once the sender is open we can read
+ * the actual name assigned by the broker from the target and that is the real temporary
+ * destination that we will return.
+ *
+ * The open of the Sender instance will also allow us to catch any security errors from
+ * the broker in the case where the user does not have authorization to access temporary
+ * destinations.
+ */
+public class AmqpTemporaryDestination extends AbstractAmqpResource<JmsDestination, Sender> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpTemporaryDestination.class);
+
+    private final AmqpConnection connection;
+    private final AmqpSession session;
+
+    public AmqpTemporaryDestination(AmqpSession session, JmsDestination destination) {
+        super(destination);
+        this.session = session;
+        this.connection = session.getConnection();
+    }
+
+    @Override
+    public void processStateChange() {
+        // TODO - We might want to check on our producer to see if it becomes closed
+        //        which might indicate that the broker purged the temporary destination.
+
+        EndpointState remoteState = endpoint.getRemoteState();
+        if (remoteState == EndpointState.ACTIVE) {
+            LOG.trace("Temporary Destination: {} is now open", this.info);
+            opened();
+        } else if (remoteState == EndpointState.CLOSED) {
+            LOG.trace("Temporary Destination: {} is now closed", this.info);
+            closed();
+        }
+    }
+
+    @Override
+    public void opened() {
+
+        // Once our producer is opened we can read the updated name from the target address.
+        String oldDestinationName = info.getName();
+        String destinationName = this.endpoint.getRemoteTarget().getAddress();
+
+        this.info.setName(destinationName);
+
+        LOG.trace("Updated temp destination to: {} from: {}", info, oldDestinationName);
+
+        super.opened();
+    }
+
+    @Override
+    protected void doOpen() {
+
+        String sourceAddress = info.getName();
+        if (info.isQueue()) {
+            sourceAddress = connection.getTempQueuePrefix() + sourceAddress;
+        } else {
+            sourceAddress = connection.getTempQueuePrefix() + sourceAddress;
+        }
+        Source source = new Source();
+        source.setAddress(sourceAddress);
+        Target target = new Target();
+        target.setDynamic(true);
+
+        String senderName = sourceAddress;
+        endpoint = session.getProtonSession().sender(senderName);
+        endpoint.setSource(source);
+        endpoint.setTarget(target);
+        endpoint.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        endpoint.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+
+        this.connection.addTemporaryDestination(this);
+    }
+
+    @Override
+    protected void doClose() {
+        this.connection.removeTemporaryDestination(this);
+    }
+
+    public AmqpConnection getConnection() {
+        return this.connection;
+    }
+
+    public AmqpSession getSession() {
+        return this.session;
+    }
+
+    public Sender getProtonSender() {
+        return this.endpoint;
+    }
+
+    public JmsDestination getJmsDestination() {
+        return this.info;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + " { " + info + "}";
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransactionContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransactionContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransactionContext.java
new file mode 100644
index 0000000..1cc6fd1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransactionContext.java
@@ -0,0 +1,269 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.jms.IllegalStateException;
+import javax.jms.TransactionRolledBackException;
+
+import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.meta.JmsTransactionId;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+import org.apache.qpid.proton.amqp.messaging.Rejected;
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.apache.qpid.proton.amqp.transaction.Coordinator;
+import org.apache.qpid.proton.amqp.transaction.Declare;
+import org.apache.qpid.proton.amqp.transaction.Declared;
+import org.apache.qpid.proton.amqp.transaction.Discharge;
+import org.apache.qpid.proton.amqp.transaction.TxnCapability;
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.message.Message;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Handles the operations surrounding AMQP transaction control.
+ *
+ * The Transaction will carry a JmsTransactionId while the Transaction is open, once a
+ * transaction has been committed or rolled back the Transaction Id is cleared.
+ */
+public class AmqpTransactionContext extends AbstractAmqpResource<JmsSessionInfo, Sender> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpTransactionContext.class);
+
+    private static final Boolean ROLLBACK_MARKER = Boolean.FALSE;
+    private static final Boolean COMMIT_MARKER = Boolean.TRUE;
+
+    private final AmqpSession session;
+    private JmsTransactionId current;
+    private final AmqpTransferTagGenerator tagGenerator = new AmqpTransferTagGenerator();
+    private final Set<AmqpConsumer> txConsumers = new LinkedHashSet<AmqpConsumer>();
+
+    private Delivery pendingDelivery;
+    private AsyncResult pendingRequest;
+
+    /**
+     * Creates a new AmqpTransaction instance.
+     *
+     * @param session
+     *        The session that owns this transaction
+     * @param info
+     *        The JmsTransactionInfo that defines this Transaction.
+     */
+    public AmqpTransactionContext(AmqpSession session) {
+        super(session.getJmsResource());
+        this.session = session;
+    }
+
+    @Override
+    public void processDeliveryUpdates() throws IOException {
+        try {
+            if (pendingDelivery != null && pendingDelivery.remotelySettled()) {
+                DeliveryState state = pendingDelivery.getRemoteState();
+                if (state instanceof Declared) {
+                    Declared declared = (Declared) state;
+                    current.setProviderHint(declared.getTxnId());
+                    pendingDelivery.settle();
+                    LOG.info("New TX started: {}", current.getProviderHint());
+                    AsyncResult request = this.pendingRequest;
+                    this.pendingRequest = null;
+                    this.pendingDelivery = null;
+                    request.onSuccess();
+                } else if (state instanceof Rejected) {
+                    LOG.info("Last TX request failed: {}", current.getProviderHint());
+                    pendingDelivery.settle();
+                    Rejected rejected = (Rejected) state;
+                    TransactionRolledBackException ex =
+                        new TransactionRolledBackException(rejected.getError().getDescription());
+                    AsyncResult request = this.pendingRequest;
+                    this.current = null;
+                    this.pendingRequest = null;
+                    this.pendingDelivery = null;
+                    postRollback();
+                    request.onFailure(ex);
+                } else {
+                    LOG.info("Last TX request succeeded: {}", current.getProviderHint());
+                    pendingDelivery.settle();
+                    AsyncResult request = this.pendingRequest;
+                    if (pendingDelivery.getContext() != null) {
+                        if (pendingDelivery.getContext().equals(COMMIT_MARKER)) {
+                            postCommit();
+                        } else {
+                            postRollback();
+                        }
+                    }
+                    this.current = null;
+                    this.pendingRequest = null;
+                    this.pendingDelivery = null;
+                    request.onSuccess();
+                }
+            }
+        } catch (Exception e) {
+            throw IOExceptionSupport.create(e);
+        }
+    }
+
+    @Override
+    protected void doOpen() {
+        Coordinator coordinator = new Coordinator();
+        coordinator.setCapabilities(TxnCapability.LOCAL_TXN, TxnCapability.MULTI_TXNS_PER_SSN);
+        Source source = new Source();
+
+        String coordinatorName = info.getSessionId().toString();
+        endpoint = session.getProtonSession().sender(coordinatorName);
+        endpoint.setSource(source);
+        endpoint.setTarget(coordinator);
+        endpoint.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        endpoint.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+    }
+
+    @Override
+    protected void doClose() {
+    }
+
+    public void begin(JmsTransactionId txId, AsyncResult request) throws Exception {
+        if (current != null) {
+            throw new IOException("Begin called while a TX is still Active.");
+        }
+
+        Message message = Message.Factory.create();
+        Declare declare = new Declare();
+        message.setBody(new AmqpValue(declare));
+
+        pendingDelivery = endpoint.delivery(tagGenerator.getNextTag());
+        pendingRequest = request;
+        current = txId;
+
+        sendTxCommand(message);
+    }
+
+    public void commit(AsyncResult request) throws Exception {
+        if (current == null) {
+            throw new IllegalStateException("Rollback called with no active Transaction.");
+        }
+
+        preCommit();
+
+        Message message = Message.Factory.create();
+        Discharge discharge = new Discharge();
+        discharge.setFail(false);
+        discharge.setTxnId((Binary) current.getProviderHint());
+        message.setBody(new AmqpValue(discharge));
+
+        pendingDelivery = endpoint.delivery(tagGenerator.getNextTag());
+        pendingDelivery.setContext(COMMIT_MARKER);
+        pendingRequest = request;
+
+        sendTxCommand(message);
+    }
+
+    public void rollback(AsyncResult request) throws Exception {
+        if (current == null) {
+            throw new IllegalStateException("Rollback called with no active Transaction.");
+        }
+
+        preRollback();
+
+        Message message = Message.Factory.create();
+        Discharge discharge = new Discharge();
+        discharge.setFail(true);
+        discharge.setTxnId((Binary) current.getProviderHint());
+        message.setBody(new AmqpValue(discharge));
+
+        pendingDelivery = endpoint.delivery(tagGenerator.getNextTag());
+        pendingDelivery.setContext(ROLLBACK_MARKER);
+        pendingRequest = request;
+
+        sendTxCommand(message);
+    }
+
+    public void registerTxConsumer(AmqpConsumer consumer) {
+        this.txConsumers.add(consumer);
+    }
+
+    public AmqpSession getSession() {
+        return this.session;
+    }
+
+    public JmsTransactionId getTransactionId() {
+        return this.current;
+    }
+
+    public Binary getAmqpTransactionId() {
+        Binary result = null;
+        if (current != null) {
+            result = (Binary) current.getProviderHint();
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return this.session.getSessionId() + ": txContext";
+    }
+
+    private void preCommit() throws Exception {
+        for (AmqpConsumer consumer : txConsumers) {
+            consumer.preCommit();
+        }
+    }
+
+    private void preRollback() throws Exception {
+        for (AmqpConsumer consumer : txConsumers) {
+            consumer.preRollback();
+        }
+    }
+
+    private void postCommit() throws Exception {
+        for (AmqpConsumer consumer : txConsumers) {
+            consumer.postCommit();
+        }
+    }
+
+    private void postRollback() throws Exception {
+        for (AmqpConsumer consumer : txConsumers) {
+            consumer.postRollback();
+        }
+    }
+
+    private void sendTxCommand(Message message) throws IOException {
+        int encodedSize = 0;
+        byte[] buffer = new byte[4 * 1024];
+        while (true) {
+            try {
+                encodedSize = message.encode(buffer, 0, buffer.length);
+                break;
+            } catch (BufferOverflowException e) {
+                buffer = new byte[buffer.length * 2];
+            }
+        }
+
+        this.endpoint.send(buffer, 0, encodedSize);
+        this.endpoint.advance();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransferTagGenerator.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransferTagGenerator.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransferTagGenerator.java
new file mode 100644
index 0000000..309561c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpTransferTagGenerator.java
@@ -0,0 +1,103 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Utility class that can generate and if enabled pool the binary tag values
+ * used to identify transfers over an AMQP link.
+ */
+public final class AmqpTransferTagGenerator {
+
+    public static final int DEFAULT_TAG_POOL_SIZE = 1024;
+
+    private long nextTagId;
+    private int maxPoolSize = DEFAULT_TAG_POOL_SIZE;
+
+    private final Set<byte[]> tagPool;
+
+    public AmqpTransferTagGenerator() {
+        this(false);
+    }
+
+    public AmqpTransferTagGenerator(boolean pool) {
+        if (pool) {
+            this.tagPool = new LinkedHashSet<byte[]>();
+        } else {
+            this.tagPool = null;
+        }
+    }
+
+    /**
+     * Retrieves the next available tag.
+     *
+     * @return a new or unused tag depending on the pool option.
+     */
+    public byte[] getNextTag() {
+        byte[] rc;
+        if (tagPool != null && !tagPool.isEmpty()) {
+            final Iterator<byte[]> iterator = tagPool.iterator();
+            rc = iterator.next();
+            iterator.remove();
+        } else {
+            try {
+                rc = Long.toHexString(nextTagId++).getBytes("UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                // This should never happen since we control the input.
+                throw new RuntimeException(e);
+            }
+        }
+        return rc;
+    }
+
+    /**
+     * When used as a pooled cache of tags the unused tags should always be returned once
+     * the transfer has been settled.
+     *
+     * @param tag
+     *        a previously borrowed tag that is no longer in use.
+     */
+    public void returnTag(byte[] data) {
+        if (tagPool != null && tagPool.size() < maxPoolSize) {
+            tagPool.add(data);
+        }
+    }
+
+    /**
+     * Gets the current max pool size value.
+     *
+     * @return the current max tag pool size.
+     */
+    public int getMaxPoolSize() {
+        return maxPoolSize;
+    }
+
+    /**
+     * Sets the max tag pool size.  If the size is smaller than the current number
+     * of pooled tags the pool will drain over time until it matches the max.
+     *
+     * @param maxPoolSize
+     *        the maximum number of tags to hold in the pool.
+     */
+    public void setMaxPoolSize(int maxPoolSize) {
+        this.maxPoolSize = maxPoolSize;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsBytesMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsBytesMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsBytesMessageFacade.java
new file mode 100644
index 0000000..1cefc2a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsBytesMessageFacade.java
@@ -0,0 +1,144 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_BYTES_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+
+import org.apache.qpid.jms.message.facade.JmsBytesMessageFacade;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+import org.fusesource.hawtbuf.Buffer;
+
+/**
+ * A JmsBytesMessageFacade that wraps around Proton AMQP Message instances to provide
+ * access to the underlying bytes contained in the message.
+ */
+public class AmqpJmsBytesMessageFacade extends AmqpJmsMessageFacade implements JmsBytesMessageFacade {
+
+    private static final String CONTENT_TYPE = "application/octet-stream";
+    private static final Buffer EMPTY_BUFFER = new Buffer(new byte[0]);
+    private static final Data EMPTY_DATA = new Data(new Binary(new byte[0]));
+
+    /**
+     * Creates a new facade instance
+     *
+     * @param connection
+     */
+    public AmqpJmsBytesMessageFacade(AmqpConnection connection) {
+        super(connection);
+        setAnnotation(JMS_MSG_TYPE, JMS_BYTES_MESSAGE);
+    }
+
+    /**
+     * Creates a new Facade around an incoming AMQP Message for dispatch to the
+     * JMS Consumer instance.
+     *
+     * @param connection
+     *        the connection that created this Facade.
+     * @param message
+     *        the incoming Message instance that is being wrapped.
+     */
+    public AmqpJmsBytesMessageFacade(AmqpConnection connection, Message message) {
+        super(connection, message);
+    }
+
+    @Override
+    public JmsBytesMessageFacade copy() {
+        AmqpJmsBytesMessageFacade copy = new AmqpJmsBytesMessageFacade(connection);
+        copyInto(copy);
+
+        copy.setContent(getContent().deepCopy());
+
+        return copy;
+    }
+
+    @Override
+    public byte getJmsMsgType() {
+        return JMS_BYTES_MESSAGE;
+    }
+
+    @Override
+    public String getContentType() {
+        return CONTENT_TYPE;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        Binary payload = getBinaryFromBody();
+        return payload != null && payload.getLength() > 0;
+    }
+
+    @Override
+    public Buffer getContent() {
+        Buffer result = EMPTY_BUFFER;
+        Binary payload = getBinaryFromBody();
+        if (payload != null && payload.getLength() > 0) {
+            result = new Buffer(payload.getArray(), payload.getArrayOffset(), payload.getLength());
+        }
+
+        return result;
+    }
+
+    @Override
+    public void setContent(Buffer content) {
+        Data body = EMPTY_DATA;
+        if (content != null) {
+            body = new Data(new Binary(content.data, content.offset, content.length));
+        }
+
+        getAmqpMessage().setBody(body);
+    }
+
+    private Binary getBinaryFromBody() {
+        Section body = getAmqpMessage().getBody();
+        Binary result = null;
+
+        if (body == null) {
+            return result;
+        }
+
+        if (body instanceof Data) {
+            Binary payload = ((Data) body).getValue();
+            if (payload != null && payload.getLength() != 0) {
+                result = payload;
+            }
+        } else if(body instanceof AmqpValue) {
+            Object value = ((AmqpValue) body).getValue();
+            if (value == null) {
+                return result;
+            }
+
+            if (value instanceof Binary) {
+                Binary payload = (Binary)value;
+                if (payload != null && payload.getLength() != 0) {
+                    result = payload;
+                }
+            } else {
+                throw new IllegalStateException("Unexpected amqp-value body content type: " + value.getClass().getSimpleName());
+            }
+        } else {
+            throw new IllegalStateException("Unexpected body content type: " + body.getClass().getSimpleName());
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMapMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMapMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMapMessageFacade.java
new file mode 100644
index 0000000..511d1e3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMapMessageFacade.java
@@ -0,0 +1,154 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MAP_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.qpid.jms.message.facade.JmsMapMessageFacade;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Wrapper around an AMQP Message instance that will be treated as a JMS MapMessage
+ * type.
+ */
+public class AmqpJmsMapMessageFacade extends AmqpJmsMessageFacade implements JmsMapMessageFacade {
+
+    private Map<String,Object> messageBodyMap;
+
+    /**
+     * Create a new facade ready for sending.
+     *
+     * @param connection
+     *        the connection instance that created this facade.
+     */
+    public AmqpJmsMapMessageFacade(AmqpConnection connection) {
+        super(connection);
+        initializeEmptyBody();
+        setAnnotation(JMS_MSG_TYPE, JMS_MAP_MESSAGE);
+    }
+
+    /**
+     * Creates a new Facade around an incoming AMQP Message for dispatch to the
+     * JMS Consumer instance.
+     *
+     * @param connection
+     *        the connection that created this Facade.
+     * @param message
+     *        the incoming Message instance that is being wrapped.
+     */
+    @SuppressWarnings("unchecked")
+    public AmqpJmsMapMessageFacade(AmqpConnection connection, Message message) {
+        super(connection, message);
+
+        Section body = getAmqpMessage().getBody();
+        if (body == null) {
+            initializeEmptyBody();
+        } else if (body instanceof AmqpValue) {
+            Object o = ((AmqpValue) body).getValue();
+            if (o == null) {
+                initializeEmptyBody();
+            } else if (o instanceof Map) {
+                messageBodyMap = (Map<String, Object>) o;
+            } else {
+                throw new IllegalStateException("Unexpected message body type: " + body.getClass().getSimpleName());
+            }
+        } else {
+            throw new IllegalStateException("Unexpected message body type: " + body.getClass().getSimpleName());
+        }
+    }
+
+    /**
+     * @return the appropriate byte value that indicates the type of message this is.
+     */
+    @Override
+    public byte getJmsMsgType() {
+        return JMS_MAP_MESSAGE;
+    }
+
+    @Override
+    public JmsMapMessageFacade copy() {
+        AmqpJmsMapMessageFacade copy = new AmqpJmsMapMessageFacade(connection);
+        copyInto(copy);
+        copy.messageBodyMap.putAll(messageBodyMap);
+        return copy;
+    }
+
+    @Override
+    public Enumeration<String> getMapNames() {
+        return Collections.enumeration(messageBodyMap.keySet());
+    }
+
+    @Override
+    public boolean itemExists(String key) {
+        return messageBodyMap.containsKey(key);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return messageBodyMap.isEmpty();
+    }
+
+    @Override
+    public Object get(String key) {
+        Object value = messageBodyMap.get(key);
+        if (value instanceof Binary) {
+            // Copy to a byte[], ensure we copy only the required portion.
+            Binary bin = ((Binary) value);
+            value = Arrays.copyOfRange(bin.getArray(), bin.getArrayOffset(), bin.getLength());
+        }
+
+        return value;
+    }
+
+    @Override
+    public void put(String key, Object value) {
+        Object entry = value;
+        if (value instanceof byte[]) {
+            entry = new Binary((byte[]) value);
+        }
+
+        messageBodyMap.put(key, entry);
+    }
+
+    @Override
+    public Object remove(String key) {
+        return messageBodyMap.remove(key);
+    }
+
+    @Override
+    public void clearBody() {
+        messageBodyMap.clear();
+    }
+
+    private void initializeEmptyBody() {
+        // Using LinkedHashMap because AMQP map equality considers order,
+        // so we should behave in as predictable a manner as possible
+        messageBodyMap = new LinkedHashMap<String, Object>();
+        getAmqpMessage().setBody(new AmqpValue(messageBodyMap));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilder.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilder.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilder.java
new file mode 100644
index 0000000..c31c50b
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageBuilder.java
@@ -0,0 +1,107 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_BYTES_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MAP_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_OBJECT_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_STREAM_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_TEXT_MESSAGE;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.qpid.jms.message.JmsBytesMessage;
+import org.apache.qpid.jms.message.JmsMapMessage;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsObjectMessage;
+import org.apache.qpid.jms.message.JmsStreamMessage;
+import org.apache.qpid.jms.message.JmsTextMessage;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Builder class used to construct the appropriate JmsMessage / JmsMessageFacade
+ * objects to wrap an incoming AMQP Message.
+ */
+public class AmqpJmsMessageBuilder {
+
+    private AmqpJmsMessageBuilder() {
+    }
+
+    /**
+     * Create a new JmsMessage and underlying JmsMessageFacade that represents the proper
+     * message type for the incoming AMQP message.
+     *
+     * @param connection
+     *        The provider AMQP Connection instance where this message arrived at.
+     * @param message
+     *        The Proton Message object that will be wrapped.
+     *
+     * @return a JmsMessage instance properly configured for dispatch to the provider listener.
+     *
+     * @throws IOException if an error occurs while creating the message objects.
+     */
+    public static JmsMessage createJmsMessage(AmqpConnection connection, Message message) throws IOException {
+
+        // First we try the easy way, if the annotation is there we don't have to work hard.
+        JmsMessage result = createFromMsgAnnotation(connection, message);
+        if (result != null) {
+            return result;
+        }
+
+        // TODO
+        throw new IOException("Could not create a JMS message from incoming message");
+    }
+
+    private static JmsMessage createFromMsgAnnotation(AmqpConnection connection, Message message) throws IOException {
+        Object annotation = getMessageAnnotation(JMS_MSG_TYPE, message);
+        if (annotation != null) {
+
+            switch ((byte) annotation) {
+                case JMS_MESSAGE:
+                    return new JmsMessage(new AmqpJmsMessageFacade(connection, message));
+                case JMS_BYTES_MESSAGE:
+                    return new JmsBytesMessage(new AmqpJmsBytesMessageFacade(connection, message));
+                case JMS_TEXT_MESSAGE:
+                    return new JmsTextMessage(new AmqpJmsTextMessageFacade(connection, message));
+                case JMS_MAP_MESSAGE:
+                    return new JmsMapMessage(new AmqpJmsMapMessageFacade(connection, message));
+                case JMS_STREAM_MESSAGE:
+                    return new JmsStreamMessage(new AmqpJmsStreamMessageFacade(connection, message));
+                case JMS_OBJECT_MESSAGE:
+                    return new JmsObjectMessage(new AmqpJmsObjectMessageFacade(connection, message));
+                default:
+                    throw new IOException("Invalid JMS Message Type annotation found in message");
+            }
+        }
+
+        return null;
+    }
+
+    private static Object getMessageAnnotation(String key, Message message) {
+        if (message.getMessageAnnotations() != null) {
+            Map<Symbol, Object> annotations = message.getMessageAnnotations().getValue();
+            return annotations.get(AmqpMessageSupport.getSymbol(key));
+        }
+
+        return null;
+    }
+}


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


[15/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedInputStream.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedInputStream.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedInputStream.java
new file mode 100644
index 0000000..c7ba887
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedInputStream.java
@@ -0,0 +1,139 @@
+/**
+ * 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.jms.transports;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An optimized buffered input stream for Tcp
+ */
+public class TcpBufferedInputStream extends FilterInputStream {
+
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
+    protected byte internalBuffer[];
+    protected int count;
+    protected int position;
+
+    public TcpBufferedInputStream(InputStream in) {
+        this(in, DEFAULT_BUFFER_SIZE);
+    }
+
+    public TcpBufferedInputStream(InputStream in, int size) {
+        super(in);
+        if (size <= 0) {
+            throw new IllegalArgumentException("Buffer size <= 0");
+        }
+        internalBuffer = new byte[size];
+    }
+
+    protected void fill() throws IOException {
+        byte[] buffer = internalBuffer;
+        count = 0;
+        position = 0;
+        int n = in.read(buffer, position, buffer.length - position);
+        if (n > 0) {
+            count = n + position;
+        }
+    }
+
+    @Override
+    public int read() throws IOException {
+        if (position >= count) {
+            fill();
+            if (position >= count) {
+                return -1;
+            }
+        }
+        return internalBuffer[position++] & 0xff;
+    }
+
+    private int readStream(byte[] b, int off, int len) throws IOException {
+        int avail = count - position;
+        if (avail <= 0) {
+            if (len >= internalBuffer.length) {
+                return in.read(b, off, len);
+            }
+            fill();
+            avail = count - position;
+            if (avail <= 0) {
+                return -1;
+            }
+        }
+        int cnt = (avail < len) ? avail : len;
+        System.arraycopy(internalBuffer, position, b, off, cnt);
+        position += cnt;
+        return cnt;
+    }
+
+    @Override
+    public int read(byte b[], int off, int len) throws IOException {
+        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+        int n = 0;
+        for (;;) {
+            int nread = readStream(b, off + n, len - n);
+            if (nread <= 0) {
+                return (n == 0) ? nread : n;
+            }
+            n += nread;
+            if (n >= len) {
+                return n;
+            }
+            // if not closed but no bytes available, return
+            InputStream input = in;
+            if (input != null && input.available() <= 0) {
+                return n;
+            }
+        }
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        if (n <= 0) {
+            return 0;
+        }
+        long avail = count - position;
+        if (avail <= 0) {
+            return in.skip(n);
+        }
+        long skipped = (avail < n) ? avail : n;
+        position += skipped;
+        return skipped;
+    }
+
+    @Override
+    public int available() throws IOException {
+        return in.available() + (count - position);
+    }
+
+    @Override
+    public boolean markSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (in != null) {
+            in.close();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedOutputStream.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedOutputStream.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedOutputStream.java
new file mode 100644
index 0000000..82f8c41
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpBufferedOutputStream.java
@@ -0,0 +1,126 @@
+/**
+ * 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.jms.transports;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An optimized buffered outputstream for Tcp
+ */
+public class TcpBufferedOutputStream extends FilterOutputStream {
+
+    private static final int BUFFER_SIZE = 8192;
+    private final byte[] buffer;
+    private final int bufferlen;
+    private int count;
+
+    /**
+     * Constructor
+     *
+     * @param out
+     */
+    public TcpBufferedOutputStream(OutputStream out) {
+        this(out, BUFFER_SIZE);
+    }
+
+    /**
+     * Creates a new buffered output stream to write data to the specified underlying output
+     * stream with the specified buffer size.
+     *
+     * @param out
+     *        the underlying output stream.
+     * @param size
+     *        the buffer size.
+     * @throws IllegalArgumentException
+     *         if size <= 0.
+     */
+    public TcpBufferedOutputStream(OutputStream out, int size) {
+        super(out);
+        if (size <= 0) {
+            throw new IllegalArgumentException("Buffer size <= 0");
+        }
+        buffer = new byte[size];
+        bufferlen = size;
+    }
+
+    /**
+     * write a byte on to the stream
+     *
+     * @param b
+     *        - byte to write
+     * @throws IOException
+     */
+    @Override
+    public void write(int b) throws IOException {
+        if ((bufferlen - count) < 1) {
+            flush();
+        }
+        buffer[count++] = (byte) b;
+    }
+
+    /**
+     * write a byte array to the stream
+     *
+     * @param b
+     *        the byte buffer
+     * @param off
+     *        the offset into the buffer
+     * @param len
+     *        the length of data to write
+     * @throws IOException
+     */
+    @Override
+    public void write(byte b[], int off, int len) throws IOException {
+        if (b != null) {
+            if ((bufferlen - count) < len) {
+                flush();
+            }
+            if (buffer.length >= len) {
+                System.arraycopy(b, off, buffer, count, len);
+                count += len;
+            } else {
+                out.write(b, off, len);
+            }
+        }
+    }
+
+    /**
+     * flush the data to the output stream This doesn't call flush on the underlying
+     * outputstream, because Tcp is particularly efficent at doing this itself ....
+     *
+     * @throws IOException
+     */
+    @Override
+    public void flush() throws IOException {
+        if (count > 0 && out != null) {
+            out.write(buffer, 0, count);
+            count = 0;
+        }
+    }
+
+    /**
+     * close this stream
+     *
+     * @throws IOException
+     */
+    @Override
+    public void close() throws IOException {
+        super.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpTransport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpTransport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpTransport.java
new file mode 100644
index 0000000..4a58c8e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TcpTransport.java
@@ -0,0 +1,270 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.transports;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vertx.java.core.AsyncResult;
+import org.vertx.java.core.AsyncResultHandler;
+import org.vertx.java.core.Handler;
+import org.vertx.java.core.Vertx;
+import org.vertx.java.core.VertxFactory;
+import org.vertx.java.core.buffer.Buffer;
+import org.vertx.java.core.net.NetClient;
+import org.vertx.java.core.net.NetSocket;
+
+/**
+ * Vertex based TCP transport for raw data packets.
+ */
+public class TcpTransport implements Transport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TcpTransport.class);
+
+    private final Vertx vertx = VertxFactory.newVertx();
+    private final NetClient client = vertx.createNetClient();
+    private final URI remoteLocation;
+    private final AtomicBoolean connected = new AtomicBoolean();
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private final AtomicReference<Throwable> connectionError = new AtomicReference<Throwable>();
+
+    private NetSocket socket;
+
+    private TransportListener listener;
+    private int socketBufferSize = 64 * 1024;
+    private int soTimeout = -1;
+    private int connectTimeout = -1;
+    private int soLinger = Integer.MIN_VALUE;
+    private boolean keepAlive;
+    private boolean tcpNoDelay = true;
+
+    /**
+     * Create a new instance of the transport.
+     *
+     * @param listener
+     *        The TransportListener that will receive data from this Transport instance.
+     * @param remoteLocation
+     *        The remote location where this transport should connection to.
+     */
+    public TcpTransport(TransportListener listener, URI remoteLocation) {
+        this.listener = listener;
+        this.remoteLocation = remoteLocation;
+    }
+
+    @Override
+    public void connect() throws IOException {
+        final CountDownLatch connectLatch = new CountDownLatch(1);
+
+        if (listener == null) {
+            throw new IllegalStateException("A transport listener must be set before connection attempts.");
+        }
+
+        configureNetClient(client);
+
+        try {
+            client.connect(remoteLocation.getPort(), remoteLocation.getHost(), new AsyncResultHandler<NetSocket>() {
+                @Override
+                public void handle(AsyncResult<NetSocket> asyncResult) {
+                    if (asyncResult.succeeded()) {
+                        socket = asyncResult.result();
+                        LOG.info("We have connected! Socket is {}", socket);
+
+                        connected.set(true);
+                        connectLatch.countDown();
+
+                        socket.dataHandler(new Handler<Buffer>() {
+                            @Override
+                            public void handle(Buffer event) {
+                                listener.onData(event);
+                            }
+                        });
+
+                        socket.closeHandler(new Handler<Void>() {
+                            @Override
+                            public void handle(Void event) {
+                                connected.set(false);
+                                listener.onTransportClosed();
+                            }
+                        });
+
+                        socket.exceptionHandler(new Handler<Throwable>() {
+                            @Override
+                            public void handle(Throwable event) {
+                                connected.set(false);
+                                listener.onTransportError(event);
+                            }
+                        });
+
+                    } else {
+                        connected.set(false);
+                        connectionError.set(asyncResult.cause());
+                        connectLatch.countDown();
+                    }
+                }
+            });
+        } catch (Throwable reason) {
+            LOG.info("Failed to connect to target Broker: {}", reason);
+            throw IOExceptionSupport.create(reason);
+        }
+
+        try {
+            connectLatch.await();
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+
+        if (connectionError.get() != null) {
+            throw IOExceptionSupport.create(connectionError.get());
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (closed.compareAndSet(false, true)) {
+            if (connected.get()) {
+                socket.close();
+                connected.set(false);
+            }
+
+            vertx.stop();
+        }
+    }
+
+    @Override
+    public void send(ByteBuffer output) throws IOException {
+        checkConnected();
+        int length = output.remaining();
+        if (length == 0) {
+            return;
+        }
+
+        byte[] copy = new byte[length];
+        output.get(copy);
+        Buffer sendBuffer = new Buffer(copy);
+
+        vertx.eventBus().send(socket.writeHandlerID(), sendBuffer);
+    }
+
+    @Override
+    public void send(org.fusesource.hawtbuf.Buffer output) throws IOException {
+        checkConnected();
+        int length = output.length();
+        if (length == 0) {
+            return;
+        }
+
+        org.fusesource.hawtbuf.Buffer clone = output.deepCopy();
+        Buffer sendBuffer = new Buffer(clone.data);
+        vertx.eventBus().send(socket.writeHandlerID(), sendBuffer);
+    }
+
+    /**
+     * Allows a subclass to configure the NetClient beyond what this transport might do.
+     *
+     * @throws IOException if an error occurs.
+     */
+    protected void configureNetClient(NetClient client) throws IOException {
+        client.setSendBufferSize(getSocketBufferSize());
+        client.setReceiveBufferSize(getSocketBufferSize());
+        client.setSoLinger(soLinger);
+        client.setTCPKeepAlive(keepAlive);
+        client.setTCPNoDelay(tcpNoDelay);
+        if (connectTimeout >= 0) {
+            client.setConnectTimeout(connectTimeout);
+        }
+    }
+
+    @Override
+    public boolean isConnected() {
+        return this.connected.get();
+    }
+
+    private void checkConnected() throws IOException {
+        if (!connected.get()) {
+            throw new IOException("Cannot send to a non-connected transport.");
+        }
+    }
+
+    @Override
+    public TransportListener getTransportListener() {
+        return this.listener;
+    }
+
+    @Override
+    public void setTransportListener(TransportListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener cannot be set to null");
+        }
+
+        this.listener = listener;
+    }
+
+    public int getSocketBufferSize() {
+        return socketBufferSize;
+    }
+
+    public void setSocketBufferSize(int socketBufferSize) {
+        this.socketBufferSize = socketBufferSize;
+    }
+
+    public int getSoTimeout() {
+        return soTimeout;
+    }
+
+    public void setSoTimeout(int soTimeout) {
+        this.soTimeout = soTimeout;
+    }
+
+    public boolean isTcpNoDelay() {
+        return tcpNoDelay;
+    }
+
+    public void setTcpNoDelay(boolean tcpNoDelay) {
+        this.tcpNoDelay = tcpNoDelay;
+    }
+
+    public int getSoLinger() {
+        return soLinger;
+    }
+
+    public void setSoLinger(int soLinger) {
+        this.soLinger = soLinger;
+    }
+
+    public boolean isKeepAlive() {
+        return keepAlive;
+    }
+
+    public void setKeepAlive(boolean keepAlive) {
+        this.keepAlive = keepAlive;
+    }
+
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(int connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/Transport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/Transport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/Transport.java
new file mode 100644
index 0000000..4cced80
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/Transport.java
@@ -0,0 +1,87 @@
+/**
+ * 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.jms.transports;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.fusesource.hawtbuf.Buffer;
+
+/**
+ * Base class for all QpidJMS Transport instances.
+ */
+public interface Transport {
+
+    /**
+     * Performs the protocol connect operation for the implemented Transport type
+     * such as a TCP socket connection etc.
+     *
+     * @throws IOException if an error occurs while attempting the connect.
+     */
+    void connect() throws IOException;
+
+    /**
+     * @return true if transport is connected or false if the connection is down.
+     */
+    boolean isConnected();
+
+    /**
+     * Close the Transport, no additional send operations are accepted.
+     *
+     * @throws IOException if an error occurs while closing the connection.
+     */
+    void close() throws IOException;
+
+    /**
+     * Sends a chunk of data over the Transport connection.
+     *
+     * @param output
+     *        The buffer of data that is to be transmitted.
+     *
+     * @throws IOException if an error occurs during the send operation.
+     */
+    void send(ByteBuffer output) throws IOException;
+
+    /**
+     * Sends a chunk of data over the Transport connection.
+     *
+     * @param output
+     *        The buffer of data that is to be transmitted.
+     *
+     * @throws IOException if an error occurs during the send operation.
+     */
+    void send(Buffer output) throws IOException;
+
+    /**
+     * Gets the currently set TransportListener instance
+     *
+     * @returns the current TransportListener or null if none set.
+     */
+    TransportListener getTransportListener();
+
+    /**
+     * Sets the Transport Listener instance that will be notified of incoming data or
+     * error events.
+     *
+     * @param listener
+     *        The new TransportListener instance to use (cannot be null).
+     *
+     * @throws IllegalArgumentException if the given listener is null.
+     */
+    void setTransportListener(TransportListener listener);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TransportListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TransportListener.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TransportListener.java
new file mode 100644
index 0000000..f244347
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/transports/TransportListener.java
@@ -0,0 +1,48 @@
+/**
+ * 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.jms.transports;
+
+import org.vertx.java.core.buffer.Buffer;
+
+/**
+ * Listener interface that should be implemented by users of the various
+ * QpidJMS Transport classes.
+ */
+public interface TransportListener {
+
+    /**
+     * Called when new incoming data has become available.
+     *
+     * @param incoming
+     *        the next incoming packet of data.
+     */
+    void onData(Buffer incoming);
+
+    /**
+     * Called if the connection state becomes closed.
+     */
+    void onTransportClosed();
+
+    /**
+     * Called when an error occurs during normal Transport operations.
+     *
+     * @param cause
+     *        the error that triggered this event.
+     */
+    void onTransportError(Throwable cause);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/AbstractMessageQueue.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/AbstractMessageQueue.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/AbstractMessageQueue.java
new file mode 100644
index 0000000..f20c21f
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/AbstractMessageQueue.java
@@ -0,0 +1,129 @@
+/**
+ * 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.jms.util;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Abstract Message Queue class used to implement the common functions of a Message Queue
+ * instance.
+ */
+public abstract class AbstractMessageQueue implements MessageQueue {
+
+    protected boolean closed;
+    protected boolean running;
+    protected Object lock = new Object();
+
+    @Override
+    public JmsInboundMessageDispatch peek() {
+        synchronized (lock) {
+            return peekFirst();
+        }
+    }
+
+    @Override
+    public JmsInboundMessageDispatch dequeue(long timeout) throws InterruptedException {
+        synchronized (lock) {
+            // Wait until the consumer is ready to deliver messages.
+            while (timeout != 0 && !closed && (isEmpty() || !running)) {
+                if (timeout == -1) {
+                    lock.wait();
+                } else {
+                    lock.wait(timeout);
+                    break;
+                }
+            }
+
+            if (closed || !running || isEmpty()) {
+                return null;
+            }
+
+            return removeFirst();
+        }
+    }
+
+    @Override
+    public JmsInboundMessageDispatch dequeueNoWait() {
+        synchronized (lock) {
+            if (closed || !running || isEmpty()) {
+                return null;
+            }
+            return removeFirst();
+        }
+    }
+
+    @Override
+    public void start() {
+        synchronized (lock) {
+            running = true;
+            lock.notifyAll();
+        }
+    }
+
+    @Override
+    public void stop() {
+        synchronized (lock) {
+            running = false;
+            lock.notifyAll();
+        }
+    }
+
+    @Override
+    public boolean isRunning() {
+        return running;
+    }
+
+    @Override
+    public void close() {
+        synchronized (lock) {
+            if (!closed) {
+                running = false;
+                closed = true;
+            }
+            lock.notifyAll();
+        }
+    }
+
+    @Override
+    public boolean isClosed() {
+        return closed;
+    }
+
+    @Override
+    public Object getLock() {
+        return lock;
+    }
+
+    /**
+     * Removes and returns the first entry in the implementation queue.  This method
+     * is always called under lock and does not need to protect itself or check running
+     * state etc.
+     *
+     * @return the first message queued in the implemented queue.
+     */
+    protected abstract JmsInboundMessageDispatch removeFirst();
+
+    /**
+     * Returns but does not remove the first entry in the implementation queue.  This method
+     * is always called under lock and does not need to protect itself or check running
+     * state etc.
+     *
+     * @return the first message queued in the implemented queue.
+     */
+    protected abstract JmsInboundMessageDispatch peekFirst();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
new file mode 100644
index 0000000..8632ee2
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ClassLoadingAwareObjectInputStream.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Proxy;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClassLoadingAwareObjectInputStream extends ObjectInputStream {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClassLoadingAwareObjectInputStream.class);
+    private static final ClassLoader FALLBACK_CLASS_LOADER = ClassLoadingAwareObjectInputStream.class.getClassLoader();
+
+    private final ClassLoader inLoader;
+
+    public ClassLoadingAwareObjectInputStream(InputStream in) throws IOException {
+        super(in);
+        inLoader = in.getClass().getClassLoader();
+    }
+
+    @Override
+    protected Class<?> resolveClass(ObjectStreamClass classDesc) throws IOException, ClassNotFoundException {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        return load(classDesc.getName(), cl, inLoader);
+    }
+
+    @Override
+    protected Class<?> resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Class<?>[] cinterfaces = new Class[interfaces.length];
+        for (int i = 0; i < interfaces.length; i++) {
+            cinterfaces[i] = load(interfaces[i], cl);
+        }
+
+        try {
+            return Proxy.getProxyClass(cl, cinterfaces);
+        } catch (IllegalArgumentException e) {
+            try {
+                return Proxy.getProxyClass(inLoader, cinterfaces);
+            } catch (IllegalArgumentException e1) {
+                // ignore
+            }
+            try {
+                return Proxy.getProxyClass(FALLBACK_CLASS_LOADER, cinterfaces);
+            } catch (IllegalArgumentException e2) {
+                // ignore
+            }
+
+            throw new ClassNotFoundException(null, e);
+        }
+    }
+
+    private Class<?> load(String className, ClassLoader... cl) throws ClassNotFoundException {
+        // check for simple types first
+        final Class<?> clazz = loadSimpleType(className);
+        if (clazz != null) {
+            LOG.trace("Loaded class: {} as simple type -> ", className, clazz);
+            return clazz;
+        }
+
+        // try the different class loaders
+        for (ClassLoader loader : cl) {
+            LOG.trace("Attempting to load class: {} using classloader: {}", className, cl);
+            try {
+                Class<?> answer = Class.forName(className, false, loader);
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("Loaded class: {} using classloader: {} -> ", new Object[] { className, cl, answer });
+                }
+                return answer;
+            } catch (ClassNotFoundException e) {
+                LOG.trace("Class not found: {} using classloader: {}", className, cl);
+                // ignore
+            }
+        }
+
+        // and then the fallback class loader
+        return Class.forName(className, false, FALLBACK_CLASS_LOADER);
+    }
+
+    /**
+     * Load a simple type
+     *
+     * @param name
+     *        the name of the class to load
+     * @return the class or <tt>null</tt> if it could not be loaded
+     */
+    public static Class<?> loadSimpleType(String name) {
+        if ("java.lang.byte[]".equals(name) || "byte[]".equals(name)) {
+            return byte[].class;
+        } else if ("java.lang.Byte[]".equals(name) || "Byte[]".equals(name)) {
+            return Byte[].class;
+        } else if ("java.lang.Object[]".equals(name) || "Object[]".equals(name)) {
+            return Object[].class;
+        } else if ("java.lang.String[]".equals(name) || "String[]".equals(name)) {
+            return String[].class;
+            // and these is common as well
+        } else if ("java.lang.String".equals(name) || "String".equals(name)) {
+            return String.class;
+        } else if ("java.lang.Boolean".equals(name) || "Boolean".equals(name)) {
+            return Boolean.class;
+        } else if ("boolean".equals(name)) {
+            return boolean.class;
+        } else if ("java.lang.Integer".equals(name) || "Integer".equals(name)) {
+            return Integer.class;
+        } else if ("int".equals(name)) {
+            return int.class;
+        } else if ("java.lang.Long".equals(name) || "Long".equals(name)) {
+            return Long.class;
+        } else if ("long".equals(name)) {
+            return long.class;
+        } else if ("java.lang.Short".equals(name) || "Short".equals(name)) {
+            return Short.class;
+        } else if ("short".equals(name)) {
+            return short.class;
+        } else if ("java.lang.Byte".equals(name) || "Byte".equals(name)) {
+            return Byte.class;
+        } else if ("byte".equals(name)) {
+            return byte.class;
+        } else if ("java.lang.Float".equals(name) || "Float".equals(name)) {
+            return Float.class;
+        } else if ("float".equals(name)) {
+            return float.class;
+        } else if ("java.lang.Double".equals(name) || "Double".equals(name)) {
+            return Double.class;
+        } else if ("double".equals(name)) {
+            return double.class;
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FactoryFinder.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FactoryFinder.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FactoryFinder.java
new file mode 100644
index 0000000..b8db705
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FactoryFinder.java
@@ -0,0 +1,210 @@
+/**
+ * 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.jms.util;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A Factory finding helper class used to locate objects that serve as Factories for
+ * other Object types.  The search an instantiate mechanism is configurable so that
+ * in a non-stand-alone environment such as OSGI the finder and be configured to work.
+ */
+public class FactoryFinder<T extends Object> {
+
+    /**
+     * The strategy that the FactoryFinder uses to find load and instantiate Objects can be
+     * changed out by calling the
+     * {@link org.apache.qpid.jms.util.FactoryFinder#setObjectFactory(org.apache.qpid.jms.util.FactoryFinder.ObjectFactory)}
+     * method with a custom implementation of ObjectFactory.
+     *
+     * The default ObjectFactory is typically changed out when running in a specialized
+     * container environment where service discovery needs to be done via the container system.
+     * For example, in an OSGi scenario.
+     */
+    public interface ObjectFactory {
+
+        /**
+         * Creates the requested factory instance.
+         *
+         * @param path
+         *        the full service path
+         *
+         * @return instance of the factory object being searched for.
+         *
+         * @throws IllegalAccessException if an error occurs while accessing the search path.
+         * @throws InstantiationException if the factory object fails on create.
+         * @throws IOException if the search encounter an IO error.
+         * @throws ClassNotFoundException if the class that is to be loaded cannot be found.
+         */
+        public Object create(String path) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException;
+
+    }
+
+    private static ObjectFactory objectFactory = new StandaloneObjectFactory();
+
+    private final ConcurrentHashMap<String, T> cachedFactories = new ConcurrentHashMap<String, T>();
+    private final String path;
+    private final Class<T> factoryType;
+
+    /**
+     * Creates a new instance of the FactoryFinder using the given search path.
+     *
+     * @param path
+     *        The path to use when searching for the factory definitions.
+     */
+    public FactoryFinder(Class<T> factoryType, String path) {
+        this.path = path;
+        this.factoryType = factoryType;
+    }
+
+    /**
+     * @return the currently configured ObjectFactory instance used to locate the Factory objects.
+     */
+    public static ObjectFactory getObjectFactory() {
+        return objectFactory;
+    }
+
+    /**
+     * Sets the ObjectFactory instance to use when searching for the Factory class.  This allows
+     * the default instance to be overridden in an environment where the basic version will not
+     * work.
+     *
+     * @param objectFactory
+     *        the new object factory to use when searching for a Factory instance.
+     */
+    public static void setObjectFactory(ObjectFactory objectFactory) {
+        FactoryFinder.objectFactory = objectFactory;
+    }
+
+    /**
+     * Creates a new instance of the given key.  The method first checks the cache of previously
+     * found factory instances for one that matches the key.  If no cached version exists then
+     * the factory will be searched for using the configured ObjectFactory instance.
+     *
+     * @param key
+     *        is the key to add to the path to find a text file containing the factory name
+     *
+     * @return a newly created instance
+     *
+     * @throws IllegalAccessException if an error occurs while accessing the search path.
+     * @throws InstantiationException if the factory object fails on create.
+     * @throws IOException if the search encounter an IO error.
+     * @throws ClassNotFoundException if the class that is to be loaded cannot be found.
+     * @throws ClassCastException if the found object is not assignable to the request factory type.
+     */
+    public T newInstance(String key) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException, ClassCastException {
+        T factory = cachedFactories.get(key);
+        if (factory == null) {
+
+            Object found = objectFactory.create(path + key);
+            if (found != null && factoryType.isInstance(found)) {
+                factory = factoryType.cast(found);
+                cachedFactories.put(key, factory);
+            } else {
+                throw new ClassCastException("Cannot cast " + found.getClass().getName() +
+                    " to " + factoryType.getName());
+            }
+        }
+
+        return factory;
+    }
+
+    /**
+     * Allow registration of a Provider factory without wiring via META-INF classes
+     *
+     * @param scheme
+     *        The URI scheme value that names the target Provider instance.
+     * @param factory
+     *        The factory to register in this finder.
+     */
+    public void registerProviderFactory(String scheme, T factory) {
+        cachedFactories.put(scheme, factory);
+    }
+
+    /**
+     * The default implementation of Object factory which works well in stand-alone applications.
+     */
+    @SuppressWarnings("rawtypes")
+    protected static class StandaloneObjectFactory implements ObjectFactory {
+        final ConcurrentHashMap<String, Class> classMap = new ConcurrentHashMap<String, Class>();
+
+        @Override
+        public Object create(final String path) throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException {
+            Class clazz = classMap.get(path);
+            if (clazz == null) {
+                clazz = loadClass(loadProperties(path));
+                classMap.put(path, clazz);
+            }
+            return clazz.newInstance();
+        }
+
+        static public Class loadClass(Properties properties) throws ClassNotFoundException, IOException {
+
+            String className = properties.getProperty("class");
+            if (className == null) {
+                throw new IOException("Expected property is missing: class");
+            }
+            Class clazz = null;
+            ClassLoader loader = Thread.currentThread().getContextClassLoader();
+            if (loader != null) {
+                try {
+                    clazz = loader.loadClass(className);
+                } catch (ClassNotFoundException e) {
+                    // ignore
+                }
+            }
+            if (clazz == null) {
+                clazz = FactoryFinder.class.getClassLoader().loadClass(className);
+            }
+
+            return clazz;
+        }
+
+        static public Properties loadProperties(String uri) throws IOException {
+            // lets try the thread context class loader first
+            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+            if (classLoader == null) {
+                classLoader = StandaloneObjectFactory.class.getClassLoader();
+            }
+            InputStream in = classLoader.getResourceAsStream(uri);
+            if (in == null) {
+                in = FactoryFinder.class.getClassLoader().getResourceAsStream(uri);
+                if (in == null) {
+                    throw new IOException("Could not find factory class for resource: " + uri);
+                }
+            }
+
+            // lets load the file
+            BufferedInputStream reader = null;
+            try {
+                reader = new BufferedInputStream(in);
+                Properties properties = new Properties();
+                properties.load(reader);
+                return properties;
+            } finally {
+                try {
+                    reader.close();
+                } catch (Exception e) {
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FifoMessageQueue.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FifoMessageQueue.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FifoMessageQueue.java
new file mode 100644
index 0000000..b50e480
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/FifoMessageQueue.java
@@ -0,0 +1,97 @@
+/**
+ * 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.jms.util;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Simple first in / first out Message Queue.
+ */
+public final class FifoMessageQueue extends AbstractMessageQueue {
+
+    protected final LinkedList<JmsInboundMessageDispatch> list = new LinkedList<JmsInboundMessageDispatch>();
+
+    @Override
+    public void enqueueFirst(JmsInboundMessageDispatch envelope) {
+        synchronized (lock) {
+            list.addFirst(envelope);
+            lock.notify();
+        }
+    }
+
+    @Override
+    public void enqueue(JmsInboundMessageDispatch envelope) {
+        synchronized (lock) {
+            list.addLast(envelope);
+            lock.notify();
+        }
+    }
+
+    @Override
+    public boolean isEmpty() {
+        synchronized (lock) {
+            return list.isEmpty();
+        }
+    }
+
+    @Override
+    public int size() {
+        synchronized (lock) {
+            return list.size();
+        }
+    }
+
+    @Override
+    public void clear() {
+        synchronized (lock) {
+            list.clear();
+        }
+    }
+
+    @Override
+    public List<JmsInboundMessageDispatch> removeAll() {
+        synchronized (lock) {
+            ArrayList<JmsInboundMessageDispatch> rc = new ArrayList<JmsInboundMessageDispatch>(list.size());
+            for (JmsInboundMessageDispatch entry : list) {
+                rc.add(entry);
+            }
+            list.clear();
+            return rc;
+        }
+    }
+
+    @Override
+    public String toString() {
+        synchronized (lock) {
+            return list.toString();
+        }
+    }
+
+    @Override
+    protected JmsInboundMessageDispatch removeFirst() {
+        return list.removeFirst();
+    }
+
+    @Override
+    protected JmsInboundMessageDispatch peekFirst() {
+        return list.peekFirst();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IOExceptionSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IOExceptionSupport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IOExceptionSupport.java
new file mode 100644
index 0000000..6caf15c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IOExceptionSupport.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms.util;
+
+import java.io.IOException;
+
+/**
+ * Used to make throwing IOException instances easier.
+ */
+public class IOExceptionSupport {
+
+    /**
+     * Checks the given cause to determine if it's already an IOException type and
+     * if not creates a new IOException to wrap it.
+     *
+     * @param cause
+     *        The initiating exception that should be cast or wrapped.
+     *
+     * @return an IOException instance.
+     */
+    public static IOException create(Throwable cause) {
+        if (cause instanceof IOException) {
+            return (IOException) cause;
+        }
+
+        String message = cause.getMessage();
+        if (message == null || message.length() == 0) {
+            message = cause.toString();
+        }
+
+        return new IOException(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IdGenerator.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IdGenerator.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IdGenerator.java
new file mode 100644
index 0000000..f07b5b4
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/IdGenerator.java
@@ -0,0 +1,228 @@
+/**
+ * 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.jms.util;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Generator for Globally unique Strings.
+ */
+public class IdGenerator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(IdGenerator.class);
+    private static final String UNIQUE_STUB;
+    private static int instanceCount;
+    private static String hostName;
+    private String seed;
+    private final AtomicLong sequence = new AtomicLong(1);
+    private int length;
+    public static final String PROPERTY_IDGENERATOR_PORT = "activemq.idgenerator.port";
+
+    static {
+        String stub = "";
+        boolean canAccessSystemProps = true;
+        try {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPropertiesAccess();
+            }
+        } catch (SecurityException se) {
+            canAccessSystemProps = false;
+        }
+
+        if (canAccessSystemProps) {
+            int idGeneratorPort = 0;
+            ServerSocket ss = null;
+            try {
+                idGeneratorPort = Integer.parseInt(System.getProperty(PROPERTY_IDGENERATOR_PORT, "0"));
+                LOG.trace("Using port {}", idGeneratorPort);
+                hostName = InetAddressUtil.getLocalHostName();
+                ss = new ServerSocket(idGeneratorPort);
+                stub = "-" + ss.getLocalPort() + "-" + System.currentTimeMillis() + "-";
+                Thread.sleep(100);
+            } catch (Exception e) {
+                if (LOG.isTraceEnabled()) {
+                    LOG.trace("could not generate unique stub by using DNS and binding to local port", e);
+                } else {
+                    LOG.warn("could not generate unique stub by using DNS and binding to local port: {} {}", e.getClass().getCanonicalName(), e.getMessage());
+                }
+
+                // Restore interrupted state so higher level code can deal with it.
+                if (e instanceof InterruptedException) {
+                    Thread.currentThread().interrupt();
+                }
+            } finally {
+                if (ss != null) {
+                    try {
+                        ss.close();
+                    } catch (IOException ioe) {
+                        if (LOG.isTraceEnabled()) {
+                            LOG.trace("Closing the server socket failed", ioe);
+                        } else {
+                            LOG.warn("Closing the server socket failed" + " due " + ioe.getMessage());
+                        }
+                    }
+                }
+            }
+        }
+
+        if (hostName == null) {
+            hostName = "localhost";
+        }
+        hostName = sanitizeHostName(hostName);
+
+        if (stub.length() == 0) {
+            stub = "-1-" + System.currentTimeMillis() + "-";
+        }
+        UNIQUE_STUB = stub;
+    }
+
+    /**
+     * Construct an IdGenerator
+     */
+    public IdGenerator(String prefix) {
+        synchronized (UNIQUE_STUB) {
+            this.seed = prefix + UNIQUE_STUB + (instanceCount++) + ":";
+            this.length = this.seed.length() + ("" + Long.MAX_VALUE).length();
+        }
+    }
+
+    public IdGenerator() {
+        this("ID:" + hostName);
+    }
+
+    /**
+     * As we have to find the host name as a side-affect of generating a unique stub, we allow
+     * it's easy retrieval here
+     *
+     * @return the local host name
+     */
+    public static String getHostName() {
+        return hostName;
+    }
+
+    /**
+     * Generate a unique id
+     *
+     * @return a unique id
+     */
+    public synchronized String generateId() {
+        StringBuilder sb = new StringBuilder(length);
+        sb.append(seed);
+        sb.append(sequence.getAndIncrement());
+        return sb.toString();
+    }
+
+    public static String sanitizeHostName(String hostName) {
+        boolean changed = false;
+
+        StringBuilder sb = new StringBuilder();
+        for (char ch : hostName.toCharArray()) {
+            // only include ASCII chars
+            if (ch < 127) {
+                sb.append(ch);
+            } else {
+                changed = true;
+            }
+        }
+
+        if (changed) {
+            String newHost = sb.toString();
+            LOG.info("Sanitized hostname from: {} to: {}", hostName, newHost);
+            return newHost;
+        } else {
+            return hostName;
+        }
+    }
+
+    /**
+     * Generate a unique ID - that is friendly for a URL or file system
+     *
+     * @return a unique id
+     */
+    public String generateSanitizedId() {
+        String result = generateId();
+        result = result.replace(':', '-');
+        result = result.replace('_', '-');
+        result = result.replace('.', '-');
+        return result;
+    }
+
+    /**
+     * From a generated id - return the seed (i.e. minus the count)
+     *
+     * @param id
+     *        the generated identifier
+     * @return the seed
+     */
+    public static String getSeedFromId(String id) {
+        String result = id;
+        if (id != null) {
+            int index = id.lastIndexOf(':');
+            if (index > 0 && (index + 1) < id.length()) {
+                result = id.substring(0, index);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * From a generated id - return the generator count
+     *
+     * @param id
+     * @return the count
+     */
+    public static long getSequenceFromId(String id) {
+        long result = -1;
+        if (id != null) {
+            int index = id.lastIndexOf(':');
+
+            if (index > 0 && (index + 1) < id.length()) {
+                String numStr = id.substring(index + 1, id.length());
+                result = Long.parseLong(numStr);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Does a proper compare on the Id's
+     *
+     * @param id1
+     * @param id2
+     * @return 0 if equal else a positive if id1 is > id2 ...
+     */
+    public static int compare(String id1, String id2) {
+        int result = -1;
+        String seed1 = IdGenerator.getSeedFromId(id1);
+        String seed2 = IdGenerator.getSeedFromId(id2);
+        if (seed1 != null && seed2 != null) {
+            result = seed1.compareTo(seed2);
+            if (result == 0) {
+                long count1 = IdGenerator.getSequenceFromId(id1);
+                long count2 = IdGenerator.getSequenceFromId(id2);
+                result = (int) (count1 - count2);
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/InetAddressUtil.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/InetAddressUtil.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/InetAddressUtil.java
new file mode 100644
index 0000000..9513892
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/InetAddressUtil.java
@@ -0,0 +1,57 @@
+/**
+ * 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.jms.util;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class InetAddressUtil {
+
+    /**
+     * When using the {@link java.net.InetAddress#getHostName()} method in an
+     * environment where neither a proper DNS lookup nor an <tt>/etc/hosts</tt>
+     * entry exists for a given host, the following exception will be thrown:
+     * <code>
+     * java.net.UnknownHostException: &lt;hostname&gt;: &lt;hostname&gt;
+     *  at java.net.InetAddress.getLocalHost(InetAddress.java:1425)
+     *   ...
+     * </code>
+     * Instead of just throwing an UnknownHostException and giving up, this
+     * method grabs a suitable hostname from the exception and prevents the
+     * exception from being thrown. If a suitable hostname cannot be acquired
+     * from the exception, only then is the <tt>UnknownHostException</tt> thrown.
+     *
+     * @return The hostname
+     * @throws UnknownHostException
+     * @see {@link java.net.InetAddress#getLocalHost()}
+     * @see {@link java.net.InetAddress#getHostName()}
+     */
+    public static String getLocalHostName() throws UnknownHostException {
+        try {
+            return (InetAddress.getLocalHost()).getHostName();
+        } catch (UnknownHostException uhe) {
+            String host = uhe.getMessage(); // host = "hostname: hostname"
+            if (host != null) {
+                int colon = host.indexOf(':');
+                if (colon > 0) {
+                    return host.substring(0, colon);
+                }
+            }
+            throw uhe;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/MessageQueue.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/MessageQueue.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/MessageQueue.java
new file mode 100644
index 0000000..a44faf6
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/MessageQueue.java
@@ -0,0 +1,131 @@
+/**
+ * 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.jms.util;
+
+import java.util.List;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Queue based storage interface for inbound Messages.
+ */
+public interface MessageQueue {
+
+    /**
+     * Adds the given message envelope to the end of the Message queue.
+     *
+     * @param envelope
+     *        The in-bound Message envelope to enqueue.
+     */
+    void enqueue(JmsInboundMessageDispatch envelope);
+
+    /**
+     * Adds the given message envelope to the front of the Message queue.
+     *
+     * @param envelope
+     *        The in-bound Message envelope to enqueue.
+     */
+    void enqueueFirst(JmsInboundMessageDispatch envelope);
+
+    /**
+     * @return true if there are no messages in the queue.
+     */
+    boolean isEmpty();
+
+    /**
+     * Return but do not remove the first element in the Message queue.
+     *
+     * @return the first element in the Queue or null if empty.
+     */
+    JmsInboundMessageDispatch peek();
+
+    /**
+     * Used to get an enqueued message. The amount of time this method blocks is
+     * based on the timeout value. - if timeout==-1 then it blocks until a
+     * message is received. - if timeout==0 then it it tries to not block at
+     * all, it returns a message if it is available - if timeout>0 then it
+     * blocks up to timeout amount of time. Expired messages will consumed by
+     * this method.
+     *
+     * @return null if we timeout or if the consumer is closed.
+     *
+     * @throws InterruptedException if the wait is interrupted.
+     */
+    JmsInboundMessageDispatch dequeue(long timeout) throws InterruptedException;
+
+    /**
+     * Used to get an enqueued Message if on exists, otherwise returns null.
+     *
+     * @return the next Message in the Queue if one exists, otherwise null.
+     */
+    JmsInboundMessageDispatch dequeueNoWait();
+
+    /**
+     * Starts the Message Queue.  An non-started Queue will always return null for
+     * any of the Queue accessor methods.
+     */
+    void start();
+
+    /**
+     * Stops the Message Queue.  Messages cannot be read from the Queue when it is in
+     * the stopped state.
+     */
+    void stop();
+
+    /**
+     * @return true if the Queue is not in the stopped or closed state.
+     */
+    boolean isRunning();
+
+    /**
+     * Closes the Message Queue.  No messages can be added or removed from the Queue
+     * once it has entered the closed state.
+     */
+    void close();
+
+    /**
+     * @return true if the Queue has been closed.
+     */
+    boolean isClosed();
+
+    /**
+     * Returns the number of Messages currently in the Queue.  This value is only
+     * meaningful at the time of the call as the size of the Queue changes rapidly
+     * as Messages arrive and are consumed.
+     *
+     * @return the current number of Messages in the Queue.
+     */
+    int size();
+
+    /**
+     * Clears the Queue of any Messages.
+     */
+    void clear();
+
+    /**
+     * Removes and returns all Messages in the Queue.
+     *
+     * @return a List containing all Messages removed from the Queue.
+     */
+    List<JmsInboundMessageDispatch> removeAll();
+
+    /**
+     * @return the lock object used to protect against concurrent access.
+     */
+    Object getLock();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PriorityMessageQueue.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PriorityMessageQueue.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PriorityMessageQueue.java
new file mode 100644
index 0000000..e0c7357
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PriorityMessageQueue.java
@@ -0,0 +1,144 @@
+/**
+ * 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.jms.util;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+/**
+ * Simple Message Priority ordered Queue.  Message envelopes are stored in the
+ * Queue based on their priority value.
+ */
+public final class PriorityMessageQueue extends AbstractMessageQueue {
+
+    private static final Integer MAX_PRIORITY = 10;
+
+    private final LinkedList<JmsInboundMessageDispatch>[] lists;
+    private int size = 0;
+
+    @SuppressWarnings("unchecked")
+    public PriorityMessageQueue() {
+        this.lists = new LinkedList[MAX_PRIORITY];
+        for (int i = 0; i < MAX_PRIORITY; i++) {
+            lists[i] = new LinkedList<JmsInboundMessageDispatch>();
+        }
+    }
+
+    @Override
+    public void enqueue(JmsInboundMessageDispatch envelope) {
+        synchronized (lock) {
+            getList(envelope).addLast(envelope);
+            this.size++;
+            lock.notify();
+        }
+    }
+
+    @Override
+    public void enqueueFirst(JmsInboundMessageDispatch envelope) {
+        synchronized (lock) {
+            getList(envelope).addFirst(envelope);
+            this.size++;
+            lock.notify();
+        }
+    }
+
+    @Override
+    public boolean isEmpty() {
+        synchronized (lock) {
+            return size == 0;
+        }
+    }
+
+    @Override
+    public int size() {
+        synchronized (lock) {
+            return size;
+        }
+    }
+
+    @Override
+    public void clear() {
+        synchronized (lock) {
+            for (int i = 0; i < MAX_PRIORITY; i++) {
+                lists[i].clear();
+            }
+            this.size = 0;
+        }
+    }
+
+    @Override
+    public List<JmsInboundMessageDispatch> removeAll() {
+        synchronized (lock) {
+            ArrayList<JmsInboundMessageDispatch> result = new ArrayList<JmsInboundMessageDispatch>(size());
+            for (int i = MAX_PRIORITY - 1; i >= 0; i--) {
+                List<JmsInboundMessageDispatch> list = lists[i];
+                result.addAll(list);
+                size -= list.size();
+                list.clear();
+            }
+            return result;
+        }
+    }
+
+    @Override
+    protected JmsInboundMessageDispatch removeFirst() {
+        if (this.size > 0) {
+            for (int i = MAX_PRIORITY - 1; i >= 0; i--) {
+                LinkedList<JmsInboundMessageDispatch> list = lists[i];
+                if (!list.isEmpty()) {
+                    this.size--;
+                    return list.removeFirst();
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected JmsInboundMessageDispatch peekFirst() {
+        if (this.size > 0) {
+            for (int i = MAX_PRIORITY - 1; i >= 0; i--) {
+                LinkedList<JmsInboundMessageDispatch> list = lists[i];
+                if (!list.isEmpty()) {
+                    return list.peekFirst();
+                }
+            }
+        }
+        return null;
+    }
+
+    private int getPriority(JmsInboundMessageDispatch envelope) {
+        int priority = javax.jms.Message.DEFAULT_PRIORITY;
+        if (envelope.getMessage() != null) {
+            try {
+                priority = Math.max(envelope.getMessage().getJMSPriority(), 0);
+            } catch (JMSException e) {
+            }
+            priority = Math.min(priority, 9);
+        }
+        return priority;
+    }
+
+    private LinkedList<JmsInboundMessageDispatch> getList(JmsInboundMessageDispatch envelope) {
+        return lists[getPriority(envelope)];
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PropertyUtil.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PropertyUtil.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PropertyUtil.java
new file mode 100644
index 0000000..8eb61d2
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/PropertyUtil.java
@@ -0,0 +1,486 @@
+/**
+ * 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.jms.util;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.beans.PropertyEditor;
+import java.beans.PropertyEditorManager;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * Utilities for properties
+ */
+public class PropertyUtil {
+
+    /**
+     * Creates a URI from the original URI and the given parameters.
+     *
+     * @param originalURI
+     *        The URI whose current parameters are remove and replaced with the given remainder
+     *        value.
+     * @param params
+     *        The URI params that should be used to replace the current ones in the target.
+     *
+     * @return a new URI that matches the original one but has its query options replaced with
+     *         the given ones.
+     *
+     * @throws URISyntaxException
+     */
+    public static URI replaceQuery(URI originalURI, Map<String, String> params) throws URISyntaxException {
+        String s = createQueryString(params);
+        if (s.length() == 0) {
+            s = null;
+        }
+        return replaceQuery(originalURI, s);
+    }
+
+    /**
+     * Creates a URI with the given query, removing an previous query value from the given URI.
+     *
+     * @param uri
+     *        The source URI whose existing query is replaced with the newly supplied one.
+     * @param query
+     *        The new URI query string that should be appended to the given URI.
+     *
+     * @return a new URI that is a combination of the original URI and the given query string.
+     * @throws URISyntaxException
+     */
+    public static URI replaceQuery(URI uri, String query) throws URISyntaxException {
+        String schemeSpecificPart = uri.getRawSchemeSpecificPart();
+        // strip existing query if any
+        int questionMark = schemeSpecificPart.lastIndexOf("?");
+        // make sure question mark is not within parentheses
+        if (questionMark < schemeSpecificPart.lastIndexOf(")")) {
+            questionMark = -1;
+        }
+        if (questionMark > 0) {
+            schemeSpecificPart = schemeSpecificPart.substring(0, questionMark);
+        }
+        if (query != null && query.length() > 0) {
+            schemeSpecificPart += "?" + query;
+        }
+        return new URI(uri.getScheme(), schemeSpecificPart, uri.getFragment());
+    }
+
+    /**
+     * Creates a URI with the given query, removing an previous query value from the given URI.
+     *
+     * @param uri
+     *        The source URI whose existing query is replaced with the newly supplied one.
+     * @param query
+     *        The new URI query string that should be appended to the given URI.
+     *
+     * @return a new URI that is a combination of the original URI and the given query string.
+     * @throws URISyntaxException
+     */
+    public static URI eraseQuery(URI uri) throws URISyntaxException {
+        return replaceQuery(uri, (String) null);
+    }
+
+    /**
+     * Given a key / value mapping, create and return a URI formatted query string that is valid
+     * and can be appended to a URI.
+     *
+     * @param options
+     *        The Mapping that will create the new Query string.
+     *
+     * @return a URI formatted query string.
+     *
+     * @throws URISyntaxException
+     */
+    public static String createQueryString(Map<String, ? extends Object> options) throws URISyntaxException {
+        try {
+            if (options.size() > 0) {
+                StringBuffer rc = new StringBuffer();
+                boolean first = true;
+                for (String key : options.keySet()) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        rc.append("&");
+                    }
+                    String value = (String) options.get(key);
+                    rc.append(URLEncoder.encode(key, "UTF-8"));
+                    rc.append("=");
+                    rc.append(URLEncoder.encode(value, "UTF-8"));
+                }
+                return rc.toString();
+            } else {
+                return "";
+            }
+        } catch (UnsupportedEncodingException e) {
+            throw (URISyntaxException) new URISyntaxException(e.toString(), "Invalid encoding").initCause(e);
+        }
+    }
+
+    /**
+     * Get properties from a URI
+     *
+     * @param uri
+     * @return <Code>Map</Code> of properties
+     * @throws Exception
+     */
+    @SuppressWarnings("unchecked")
+    public static Map<String, String> parseParameters(URI uri) throws Exception {
+        return uri.getQuery() == null ? Collections.EMPTY_MAP : parseQuery(stripPrefix(uri.getQuery(), "?"));
+    }
+
+    /**
+     * Parse properties from a named resource -eg. a URI or a simple name e.g.
+     * foo?name="fred"&size=2
+     *
+     * @param uri
+     * @return <Code>Map</Code> of properties
+     * @throws Exception
+     */
+    @SuppressWarnings("unchecked")
+    public static Map<String, String> parseParameters(String uri) throws Exception {
+        return uri == null ? Collections.EMPTY_MAP : parseQuery(stripUpto(uri, '?'));
+    }
+
+    /**
+     * Get properties from a uri
+     *
+     * @param uri
+     * @return <Code>Map</Code> of properties
+     *
+     * @throws Exception
+     */
+    public static Map<String, String> parseQuery(String uri) throws Exception {
+        if (uri != null) {
+            Map<String, String> rc = new HashMap<String, String>();
+            if (uri != null) {
+                String[] parameters = uri.split("&");
+                for (int i = 0; i < parameters.length; i++) {
+                    int p = parameters[i].indexOf("=");
+                    if (p >= 0) {
+                        String name = URLDecoder.decode(parameters[i].substring(0, p), "UTF-8");
+                        String value = URLDecoder.decode(parameters[i].substring(p + 1), "UTF-8");
+                        rc.put(name, value);
+                    } else {
+                        rc.put(parameters[i], null);
+                    }
+                }
+            }
+            return rc;
+        }
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Given a map of properties, filter out only those prefixed with the given value, the
+     * values filtered are returned in a new Map instance.
+     *
+     * @param properties
+     *        The map of properties to filter.
+     * @param optionPrefix
+     *        The prefix value to use when filtering.
+     *
+     * @return a filter map with only values that match the given prefix.
+     */
+    public static Map<String, String> filterProperties(Map<String, String> props, String optionPrefix) {
+        if (props == null) {
+            throw new IllegalArgumentException("props was null.");
+        }
+
+        HashMap<String, String> rc = new HashMap<String, String>(props.size());
+
+        for (Iterator<String> iter = props.keySet().iterator(); iter.hasNext();) {
+            String name = iter.next();
+            if (name.startsWith(optionPrefix)) {
+                String value = props.get(name);
+                name = name.substring(optionPrefix.length());
+                rc.put(name, value);
+                iter.remove();
+            }
+        }
+
+        return rc;
+    }
+
+    /**
+     * Add bean properties to a URI
+     *
+     * @param uri
+     * @param bean
+     * @return <Code>Map</Code> of properties
+     * @throws Exception
+     */
+    public static String addPropertiesToURIFromBean(String uri, Object bean) throws Exception {
+        Map<String, String> props = PropertyUtil.getProperties(bean);
+        return PropertyUtil.addPropertiesToURI(uri, props);
+    }
+
+    /**
+     * Add properties to a URI
+     *
+     * @param uri
+     * @param props
+     * @return uri with properties on
+     * @throws Exception
+     */
+    public static String addPropertiesToURI(URI uri, Map<String, String> props) throws Exception {
+        return addPropertiesToURI(uri.toString(), props);
+    }
+
+    /**
+     * Add properties to a URI
+     *
+     * @param uri
+     * @param props
+     * @return uri with properties on
+     * @throws Exception
+     */
+    public static String addPropertiesToURI(String uri, Map<String, String> props) throws Exception {
+        String result = uri;
+        if (uri != null && props != null) {
+            StringBuilder base = new StringBuilder(stripBefore(uri, '?'));
+            Map<String, String> map = parseParameters(uri);
+            if (!map.isEmpty()) {
+                map.putAll(props);
+            }
+            if (!map.isEmpty()) {
+                base.append('?');
+                boolean first = true;
+                for (Map.Entry<String, String> entry : map.entrySet()) {
+                    if (!first) {
+                        base.append('&');
+                    }
+                    first = false;
+                    base.append(entry.getKey()).append("=").append(entry.getValue());
+                }
+                result = base.toString();
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Set properties on an object using the provided map. The return value indicates if all
+     * properties from the given map were set on the target object.
+     *
+     * @param target
+     *        the object whose properties are to be set from the map options.
+     * @param props
+     *        the properties that should be applied to the given object.
+     *
+     * @return true if all values in the props map were applied to the target object.
+     */
+    public static boolean setProperties(Object target, Map<String, String> props) {
+        if (target == null) {
+            throw new IllegalArgumentException("target was null.");
+        }
+        if (props == null) {
+            throw new IllegalArgumentException("props was null.");
+        }
+
+        int setCounter = 0;
+
+        for (Map.Entry<String, String> entry : props.entrySet()) {
+            if (setProperty(target, entry.getKey(), entry.getValue())) {
+                setCounter++;
+            }
+        }
+
+        return setCounter == props.size();
+    }
+
+    /**
+     * Get properties from an object
+     *
+     * @param object
+     * @return <Code>Map</Code> of properties
+     * @throws Exception
+     */
+    public static Map<String, String> getProperties(Object object) throws Exception {
+        Map<String, String> props = new LinkedHashMap<String, String>();
+        BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
+        Object[] NULL_ARG = {};
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        if (propertyDescriptors != null) {
+            for (int i = 0; i < propertyDescriptors.length; i++) {
+                PropertyDescriptor pd = propertyDescriptors[i];
+                if (pd.getReadMethod() != null && !pd.getName().equals("class") && !pd.getName().equals("properties") && !pd.getName().equals("reference")) {
+                    Object value = pd.getReadMethod().invoke(object, NULL_ARG);
+                    if (value != null) {
+                        if (value instanceof Boolean || value instanceof Number || value instanceof String || value instanceof URI || value instanceof URL) {
+                            props.put(pd.getName(), ("" + value));
+                        } else if (value instanceof SSLContext) {
+                            // ignore this one..
+                        } else {
+                            Map<String, String> inner = getProperties(value);
+                            for (Map.Entry<String, String> entry : inner.entrySet()) {
+                                props.put(pd.getName() + "." + entry.getKey(), entry.getValue());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return props;
+    }
+
+    /**
+     * Find a specific property getter in a given object based on a property name.
+     *
+     * @param object
+     *        the object to search.
+     * @param name
+     *        the property name to search for.
+     *
+     * @return the result of invoking the specific property get method.
+     *
+     * @throws Exception if an error occurs while searching the object's bean info.
+     */
+    public static Object getProperty(Object object, String name) throws Exception {
+        BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
+        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
+        if (propertyDescriptors != null) {
+            for (int i = 0; i < propertyDescriptors.length; i++) {
+                PropertyDescriptor pd = propertyDescriptors[i];
+                if (pd.getReadMethod() != null && pd.getName().equals(name)) {
+                    return pd.getReadMethod().invoke(object);
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Set a property
+     *
+     * @param target
+     * @param name
+     * @param value
+     * @return true if set
+     */
+    public static boolean setProperty(Object target, String name, Object value) {
+        try {
+            int dotPos = name.indexOf(".");
+            while (dotPos >= 0) {
+                String getterName = name.substring(0, dotPos);
+                target = getProperty(target, getterName);
+                name = name.substring(dotPos + 1);
+                dotPos = name.indexOf(".");
+            }
+
+            Class<? extends Object> clazz = target.getClass();
+            Method setter = findSetterMethod(clazz, name);
+            if (setter == null) {
+                return false;
+            }
+            // If the type is null or it matches the needed type, just use the
+            // value directly
+            if (value == null || value.getClass() == setter.getParameterTypes()[0]) {
+                setter.invoke(target, new Object[] { value });
+            } else {
+                // We need to convert it
+                setter.invoke(target, new Object[] { convert(value, setter.getParameterTypes()[0]) });
+            }
+            return true;
+        } catch (Throwable ignore) {
+            return false;
+        }
+    }
+
+    /**
+     * Return a String past a prefix
+     *
+     * @param value
+     * @param prefix
+     * @return stripped
+     */
+    public static String stripPrefix(String value, String prefix) {
+        if (value.startsWith(prefix)) {
+            return value.substring(prefix.length());
+        }
+        return value;
+    }
+
+    /**
+     * Return a String from to a character
+     *
+     * @param value
+     * @param c
+     * @return stripped
+     */
+    public static String stripUpto(String value, char c) {
+        String result = null;
+        int index = value.indexOf(c);
+        if (index > 0) {
+            result = value.substring(index + 1);
+        }
+        return result;
+    }
+
+    /**
+     * Return a String up to and including character
+     *
+     * @param value
+     * @param c
+     * @return stripped
+     */
+    public static String stripBefore(String value, char c) {
+        String result = value;
+        int index = value.indexOf(c);
+        if (index > 0) {
+            result = value.substring(0, index);
+        }
+        return result;
+    }
+
+    private static Method findSetterMethod(Class<? extends Object> clazz, String name) {
+        // Build the method name.
+        name = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
+        Method[] methods = clazz.getMethods();
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+            Class<? extends Object> params[] = method.getParameterTypes();
+            if (method.getName().equals(name) && params.length == 1) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    private static Object convert(Object value, Class<?> type) throws Exception {
+        PropertyEditor editor = PropertyEditorManager.findEditor(type);
+        if (editor != null) {
+            editor.setAsText(value.toString());
+            return editor.getValue();
+        }
+        if (type == URI.class) {
+            return new URI(value.toString());
+        }
+        return null;
+    }
+}


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


[03/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsClientAckTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsClientAckTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsClientAckTest.java
new file mode 100644
index 0000000..aa97a60
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsClientAckTest.java
@@ -0,0 +1,361 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.After;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test that Session CLIENT_ACKNOWLEDGE works as expected.
+ */
+public class JmsClientAckTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsClientAckTest.class);
+
+    private Connection connection;
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        connection.close();
+        super.tearDown();
+    }
+
+    @Test(timeout = 60000)
+    public void testAckedMessageAreConsumed() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Hello"));
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        // Consume the message...
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message msg = consumer.receive(1000);
+        assertNotNull(msg);
+        msg.acknowledge();
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+
+        connection.close();
+    }
+
+    @Test(timeout = 60000)
+    public void testLastMessageAcked() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Hello"));
+        producer.send(session.createTextMessage("Hello2"));
+        producer.send(session.createTextMessage("Hello3"));
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(3, proxy.getQueueSize());
+
+        // Consume the message...
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message msg = consumer.receive(1000);
+        assertNotNull(msg);
+        msg = consumer.receive(1000);
+        assertNotNull(msg);
+        msg = consumer.receive(1000);
+        assertNotNull(msg);
+        msg.acknowledge();
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout = 60000)
+    public void testUnAckedMessageAreNotConsumedOnSessionClose() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Hello"));
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        // Consume the message...but don't ack it.
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message msg = consumer.receive(1000);
+        assertNotNull(msg);
+        session.close();
+
+        assertEquals(1, proxy.getQueueSize());
+
+        // Consume the message...and this time we ack it.
+        session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        consumer = session.createConsumer(queue);
+        msg = consumer.receive(2000);
+        assertNotNull(msg);
+        msg.acknowledge();
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout = 60000)
+    public void testAckedMessageAreConsumedByAsync() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Hello"));
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        // Consume the message...
+        MessageConsumer consumer = session.createConsumer(queue);
+        consumer.setMessageListener(new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+                try {
+                    message.acknowledge();
+                } catch (JMSException e) {
+                    LOG.warn("Unexpected exception on acknowledge: {}", e.getMessage());
+                }
+            }
+        });
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout = 60000)
+    public void testUnAckedAsyncMessageAreNotConsumedOnSessionClose() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Hello"));
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        // Consume the message...
+        MessageConsumer consumer = session.createConsumer(queue);
+        consumer.setMessageListener(new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+                // Don't ack the message.
+            }
+        });
+
+        session.close();
+        assertEquals(1, proxy.getQueueSize());
+
+        // Now we consume and ack the Message.
+        session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        consumer = session.createConsumer(queue);
+        Message msg = consumer.receive(2000);
+        assertNotNull(msg);
+        msg.acknowledge();
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout=90000)
+    public void testAckMarksAllConsumerMessageAsConsumed() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+
+        final int MSG_COUNT = 30;
+        final AtomicReference<Message> lastMessage = new AtomicReference<Message>();
+        final CountDownLatch done = new CountDownLatch(MSG_COUNT);
+
+        MessageListener myListener = new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+                lastMessage.set(message);
+                done.countDown();
+            }
+        };
+
+        MessageConsumer consumer1 = session.createConsumer(queue);
+        consumer1.setMessageListener(myListener);
+        MessageConsumer consumer2 = session.createConsumer(queue);
+        consumer2.setMessageListener(myListener);
+        MessageConsumer consumer3 = session.createConsumer(queue);
+        consumer3.setMessageListener(myListener);
+
+        MessageProducer producer = session.createProducer(queue);
+        for (int i = 0; i < MSG_COUNT; ++i) {
+            producer.send(session.createTextMessage("Hello: " + i));
+        }
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(MSG_COUNT, proxy.getQueueSize());
+
+        assertTrue("Failed to consume all messages.", done.await(20, TimeUnit.SECONDS));
+        assertNotNull(lastMessage.get());
+        assertEquals(MSG_COUNT, proxy.getInFlightCount());
+
+        lastMessage.get().acknowledge();
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout=60000)
+    public void testUnackedAreRecovered() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session consumerSession = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = consumerSession.createQueue(name.getMethodName());
+        MessageConsumer consumer = consumerSession.createConsumer(queue);
+        Session producerSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageProducer producer = producerSession.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+        TextMessage sent1 = producerSession.createTextMessage();
+        sent1.setText("msg1");
+        producer.send(sent1);
+        TextMessage sent2 = producerSession.createTextMessage();
+        sent1.setText("msg2");
+        producer.send(sent2);
+        TextMessage sent3 = producerSession.createTextMessage();
+        sent1.setText("msg3");
+        producer.send(sent3);
+
+        consumer.receive(5000);
+        Message rec2 = consumer.receive(5000);
+        consumer.receive(5000);
+        rec2.acknowledge();
+
+        TextMessage sent4 = producerSession.createTextMessage();
+        sent4.setText("msg4");
+        producer.send(sent4);
+
+        Message rec4 = consumer.receive(5000);
+        assertNotNull(rec4);
+        assertTrue(rec4.equals(sent4));
+        consumerSession.recover();
+        rec4 = consumer.receive(5000);
+        assertNotNull(rec4);
+        assertTrue(rec4.equals(sent4));
+        assertTrue(rec4.getJMSRedelivered());
+        rec4.acknowledge();
+    }
+
+    @Test(timeout=60000)
+    public void testRecoverRedelivery() throws Exception {
+        final CountDownLatch redelivery = new CountDownLatch(6);
+        connection = createAmqpConnection();
+        connection.start();
+
+        final Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        consumer.setMessageListener(new MessageListener() {
+            @Override
+            public void onMessage(Message message) {
+                try {
+                    LOG.info("Got message: " + message.getJMSMessageID());
+                    if (message.getJMSRedelivered()) {
+                        LOG.info("It's a redelivery.");
+                        redelivery.countDown();
+                    }
+                    LOG.info("calling recover() on the session to force redelivery.");
+                    session.recover();
+                } catch (JMSException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+
+        connection.start();
+
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("test"));
+
+        assertTrue("we got 6 redeliveries", redelivery.await(20, TimeUnit.SECONDS));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsConsumerPriorityDispatchTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsConsumerPriorityDispatchTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsConsumerPriorityDispatchTest.java
new file mode 100644
index 0000000..018d6bc
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsConsumerPriorityDispatchTest.java
@@ -0,0 +1,123 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test for Message priority ordering.
+ */
+public class JmsConsumerPriorityDispatchTest extends AmqpTestSupport {
+
+    private Connection connection;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        connection = createAmqpConnection();
+    }
+
+    @Test(timeout = 60000)
+    public void testPrefetchedMessageArePriorityOrdered() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message message = null;
+
+        for (int i = 0; i < 10; i++) {
+            message = session.createTextMessage();
+            producer.setPriority(i);
+            producer.send(message);
+        }
+
+        // Wait for all sent to be dispatched.
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        Wait.waitFor(new Wait.Condition() {
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getInFlightCount() == 10;
+            }
+        });
+
+        // We need to make sure that all messages are in the prefetch buffer.
+        TimeUnit.SECONDS.sleep(4);
+
+        for (int i = 9; i >= 0; i--) {
+            message = consumer.receive(5000);
+            assertNotNull(message);
+            assertEquals(i, message.getJMSPriority());
+        }
+    }
+
+    @Test(timeout = 60000)
+    public void testPrefetchedMessageAreNotPriorityOrdered() throws Exception {
+        // We are assuming that Broker side priority support is not enabled in the create
+        // broker method in AmqpTestSupport.  If that changes then this test will sometimes
+        // fail.
+        ((JmsConnection) connection).setMessagePrioritySupported(false);
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message message = null;
+
+        for (int i = 0; i < 10; i++) {
+            message = session.createTextMessage();
+            producer.setPriority(i);
+            producer.send(message);
+        }
+
+        // Wait for all sent to be dispatched.
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        Wait.waitFor(new Wait.Condition() {
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getInFlightCount() == 10;
+            }
+        });
+
+        // We need to make sure that all messages are in the prefetch buffer.
+        TimeUnit.SECONDS.sleep(4);
+
+        for (int i = 0; i < 10; i++) {
+            message = consumer.receive(5000);
+            assertNotNull(message);
+            assertEquals(i, message.getJMSPriority());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsCreateResourcesInOnMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsCreateResourcesInOnMessageTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsCreateResourcesInOnMessageTest.java
new file mode 100644
index 0000000..dbbee26
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsCreateResourcesInOnMessageTest.java
@@ -0,0 +1,94 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Test;
+
+/**
+ * Test the case where messages are sent and consumers are created in onMessage.
+ */
+public class JmsCreateResourcesInOnMessageTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateProducerInOnMessage() throws Exception {
+        Connection connection = createAmqpConnection();
+        connection.start();
+
+        final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        final Queue forwardQ = session.createQueue(name.getMethodName() + "-forwarded");
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("TEST-MESSAGE"));
+        producer.close();
+
+        final QueueViewMBean proxy = getProxyToQueue(queue.getQueueName());
+        assertEquals(1, proxy.getQueueSize());
+
+        consumer.setMessageListener(new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+
+                try {
+                    LOG.debug("Received async message: {}", message);
+                    MessageProducer producer = session.createProducer(forwardQ);
+                    producer.send(message);
+                    LOG.debug("forwarded async message: {}", message);
+                } catch (Throwable e) {
+                    LOG.debug("Caught exception: {}", e);
+                    throw new RuntimeException(e.getMessage());
+                }
+            }
+        });
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+
+        final QueueViewMBean proxy2 = getProxyToQueue(forwardQ.getQueueName());
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy2.getQueueSize() == 1;
+            }
+        }));
+
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsDurableSubscriberTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsDurableSubscriberTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsDurableSubscriberTest.java
new file mode 100644
index 0000000..5994184
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsDurableSubscriberTest.java
@@ -0,0 +1,143 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicSubscriber;
+
+import org.apache.activemq.broker.jmx.TopicViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test Durable Topic Subscriber functionality.
+ */
+public class JmsDurableSubscriberTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsMessageConsumerTest.class);
+
+    @Override
+    public boolean isPersistent() {
+        return true;
+    }
+
+    @Test(timeout = 60000)
+    public void testCreateDuableSubscriber() throws Exception {
+        connection = createAmqpConnection();
+        connection.setClientID("DURABLE-AMQP");
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Topic topic = session.createTopic(name.getMethodName());
+        session.createDurableSubscriber(topic, name.getMethodName() + "-subscriber");
+
+        TopicViewMBean proxy = getProxyToTopic(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+
+        assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length);
+    }
+
+    @Test(timeout = 60000)
+    public void testDurableGoesOfflineAndReturns() throws Exception {
+        connection = createAmqpConnection();
+        connection.setClientID("DURABLE-AMQP");
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Topic topic = session.createTopic(name.getMethodName());
+        TopicSubscriber subscriber = session.createDurableSubscriber(topic, name.getMethodName() + "-subscriber");
+
+        TopicViewMBean proxy = getProxyToTopic(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+
+        assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length);
+        assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length);
+
+        subscriber.close();
+
+        assertEquals(0, brokerService.getAdminView().getDurableTopicSubscribers().length);
+        assertEquals(1, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length);
+
+        subscriber = session.createDurableSubscriber(topic, name.getMethodName() + "-subscriber");
+
+        assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length);
+        assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length);
+    }
+
+    @Test(timeout = 60000)
+    public void testOfflineSubscriberGetsItsMessages() throws Exception {
+        connection = createAmqpConnection();
+        connection.setClientID("DURABLE-AMQP");
+        connection.start();
+
+        final int MSG_COUNT = 5;
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Topic topic = session.createTopic(name.getMethodName());
+        TopicSubscriber subscriber = session.createDurableSubscriber(topic, name.getMethodName() + "-subscriber");
+
+        TopicViewMBean proxy = getProxyToTopic(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+        assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length);
+        assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length);
+
+        subscriber.close();
+
+        assertEquals(0, brokerService.getAdminView().getDurableTopicSubscribers().length);
+        assertEquals(1, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length);
+
+        MessageProducer producer = session.createProducer(topic);
+        for (int i = 0; i < MSG_COUNT; i++) {
+            producer.send(session.createTextMessage("Message: " + i));
+        }
+        producer.close();
+
+        LOG.info("Bringing offline subscription back online.");
+        subscriber = session.createDurableSubscriber(topic, name.getMethodName() + "-subscriber");
+
+        assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length);
+        assertEquals(0, brokerService.getAdminView().getInactiveDurableTopicSubscribers().length);
+
+        final CountDownLatch messages = new CountDownLatch(MSG_COUNT);
+        subscriber.setMessageListener(new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+                LOG.info("Consumer got a message: {}", message);
+                messages.countDown();
+            }
+        });
+
+        assertTrue("Only recieved messages: " + messages.getCount(), messages.await(30, TimeUnit.SECONDS));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerClosedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerClosedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerClosedTest.java
new file mode 100644
index 0000000..8fbcbad
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerClosedTest.java
@@ -0,0 +1,89 @@
+/**
+ * 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.jms.consumer;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Tests MessageConsumer method contracts after the MessageConsumer is closed.
+ */
+public class JmsMessageConsumerClosedTest extends AmqpTestSupport {
+
+    protected MessageConsumer consumer;
+
+    protected MessageConsumer createConsumer() throws Exception {
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        consumer.close();
+        return consumer;
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        consumer = createConsumer();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetMessageSelectorFails() throws JMSException {
+        consumer.getMessageSelector();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetMessageListenerFails() throws JMSException {
+        consumer.getMessageListener();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetMessageListenerFails() throws JMSException {
+        consumer.setMessageListener(new MessageListener() {
+            @Override
+            public void onMessage(Message message) {
+            }
+        });
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testRreceiveFails() throws JMSException {
+        consumer.receive();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testRreceiveTimedFails() throws JMSException {
+        consumer.receive(11);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testRreceiveNoWaitFails() throws JMSException {
+        consumer.receiveNoWait();
+    }
+
+    @Test(timeout=30000)
+    public void testClose() throws JMSException {
+        consumer.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerFailedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerFailedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerFailedTest.java
new file mode 100644
index 0000000..85b4b37
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerFailedTest.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.jms.consumer;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.Wait;
+
+/**
+ * Tests MessageConsumer method contracts after the MessageConsumer connection fails.
+ */
+public class JmsMessageConsumerFailedTest extends JmsMessageConsumerClosedTest {
+
+    @Override
+    protected MessageConsumer createConsumer() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        connection.setExceptionListener(new ExceptionListener() {
+
+            @Override
+            public void onException(JMSException exception) {
+                latch.countDown();
+            }
+        });
+        connection.start();
+        stopPrimaryBroker();
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        final JmsConnection jmsConnection = (JmsConnection) connection;
+        assertTrue(Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return !jmsConnection.isConnected();
+            }
+        }));
+        return consumer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerTest.java
new file mode 100644
index 0000000..609b46a
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageConsumerTest.java
@@ -0,0 +1,467 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.InvalidSelectorException;
+import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.broker.jmx.TopicViewMBean;
+import org.apache.qpid.jms.JmsMessageAvailableListener;
+import org.apache.qpid.jms.JmsMessageConsumer;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test for basic JMS MessageConsumer functionality.
+ */
+public class JmsMessageConsumerTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsMessageConsumerTest.class);
+
+    @Override
+    public boolean isPersistent() {
+        return true;
+    }
+
+    @Test(timeout = 60000)
+    public void testCreateMessageConsumer() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        session.createConsumer(queue);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testSyncConsumeFromQueue() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        sendToAmqQueue(1);
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        assertNotNull("Failed to receive any message.", consumer.receive(2000));
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout = 60000)
+    public void testSyncConsumeFromTopic() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Topic topic = session.createTopic(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(topic);
+
+        sendToAmqTopic(1);
+
+        final TopicViewMBean proxy = getProxyToTopic(name.getMethodName());
+        //assertEquals(1, proxy.getQueueSize());
+
+        assertNotNull("Failed to receive any message.", consumer.receive(2000));
+
+        assertTrue("Published message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout = 60000)
+    public void testMessageAvailableConsumer() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        final int MSG_COUNT = 10;
+        final AtomicInteger available = new AtomicInteger();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        ((JmsMessageConsumer) consumer).setAvailableListener(new JmsMessageAvailableListener() {
+
+            @Override
+            public void onMessageAvailable(MessageConsumer consumer) {
+                available.incrementAndGet();
+            }
+        });
+
+        sendToAmqQueue(MSG_COUNT);
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(MSG_COUNT, proxy.getQueueSize());
+
+        assertTrue("Listener not notified of correct number of messages.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return available.get() == MSG_COUNT;
+            }
+        }));
+
+        // All should be immediately ready for consume.
+        for (int i = 0; i < MSG_COUNT; ++i) {
+            assertNotNull(consumer.receiveNoWait());
+        }
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    /**
+     * Test to check if consumer thread wakes up inside a receive(timeout) after
+     * a message is dispatched to the consumer.  We do a long poll here to ensure
+     * that a blocked receive with timeout does eventually get a Message.  We don't
+     * want to test the short poll and retry case here since that's not what we are
+     * testing.
+     *
+     * @throws Exception
+     */
+    @Test(timeout=60000)
+    public void testConsumerReceiveBeforeMessageDispatched() throws Exception {
+        final Connection connection = createAmqpConnection();
+        this.connection = connection;
+        connection.start();
+
+        final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        final Queue queue = session.createQueue(name.getMethodName());
+
+        Thread t = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    TimeUnit.SECONDS.sleep(10);
+                    MessageProducer producer = session.createProducer(queue);
+                    producer.send(session.createTextMessage("Hello"));
+                } catch (Exception e) {
+                    LOG.warn("Caught during message send: {}", e.getMessage());
+                }
+            }
+        };
+        t.start();
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message msg = consumer.receive(60000);
+        assertNotNull(msg);
+    }
+
+    @Test(timeout=60000)
+    public void testAsynchronousMessageConsumption() throws Exception {
+        final int msgCount = 4;
+        final Connection connection = createAmqpConnection();
+        final AtomicInteger counter = new AtomicInteger(0);
+        final CountDownLatch done = new CountDownLatch(1);
+        this.connection = connection;
+
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+
+        consumer.setMessageListener(new MessageListener() {
+            @Override
+            public void onMessage(Message m) {
+                LOG.debug("Async consumer got Message: {}", m);
+                counter.incrementAndGet();
+                if (counter.get() == msgCount) {
+                    done.countDown();
+                }
+            }
+        });
+
+        sendToAmqQueue(msgCount);
+        assertTrue(done.await(1000, TimeUnit.MILLISECONDS));
+        TimeUnit.SECONDS.sleep(1);
+        assertEquals(msgCount, counter.get());
+    }
+
+    @Test(timeout=60000)
+    public void testSyncReceiveFailsWhenListenerSet() throws Exception {
+        final int msgCount = 4;
+        final Connection connection = createAmqpConnection();
+        final AtomicInteger counter = new AtomicInteger(0);
+        final CountDownLatch done = new CountDownLatch(1);
+        this.connection = connection;
+
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+
+        consumer.setMessageListener(new MessageListener() {
+            @Override
+            public void onMessage(Message m) {
+                LOG.debug("Async consumer got Message: {}", m);
+                counter.incrementAndGet();
+                if (counter.get() == msgCount) {
+                    done.countDown();
+                }
+            }
+        });
+
+        try {
+            consumer.receive();
+            fail("Should have thrown an exception.");
+        } catch (JMSException ex) {
+        }
+
+        try {
+            consumer.receive(1000);
+            fail("Should have thrown an exception.");
+        } catch (JMSException ex) {
+        }
+
+        try {
+            consumer.receiveNoWait();
+            fail("Should have thrown an exception.");
+        } catch (JMSException ex) {
+        }
+    }
+
+    @Test(timeout=60000)
+    public void testSetMessageListenerAfterStartAndSend() throws Exception {
+        final int msgCount = 4;
+        final Connection connection = createAmqpConnection();
+        final AtomicInteger counter = new AtomicInteger(0);
+        final CountDownLatch done = new CountDownLatch(1);
+        this.connection = connection;
+
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        sendToAmqQueue(msgCount);
+
+        consumer.setMessageListener(new MessageListener() {
+            @Override
+            public void onMessage(Message m) {
+                LOG.debug("Async consumer got Message: {}", m);
+                counter.incrementAndGet();
+                if (counter.get() == msgCount) {
+                    done.countDown();
+                }
+            }
+        });
+
+        assertTrue(done.await(1000, TimeUnit.MILLISECONDS));
+        TimeUnit.SECONDS.sleep(1);
+        assertEquals(msgCount, counter.get());
+    }
+
+    @Test(timeout=60000)
+    public void testNoReceivedMessagesWhenConnectionNotStarted() throws Exception {
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        sendToAmqQueue(3);
+        assertNull(consumer.receive(2000));
+    }
+
+    @Test(timeout = 60000)
+    public void testMessagesAreAckedAMQProducer() throws Exception {
+        int messagesSent = 3;
+        assertTrue(brokerService.isPersistent());
+
+        connection = createActiveMQConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer p = session.createProducer(queue);
+        TextMessage message = null;
+        for (int i=0; i < messagesSent; i++) {
+            message = session.createTextMessage();
+            String messageText = "Hello " + i + " sent at " + new java.util.Date().toString();
+            message.setText(messageText);
+            LOG.debug(">>>> Sent [{}]", messageText);
+            p.send(message);
+        }
+
+        // After the first restart we should get all messages sent above
+        restartPrimaryBroker();
+        int messagesReceived = readAllMessages();
+        assertEquals(messagesSent, messagesReceived);
+
+        // This time there should be no messages on this queue
+        restartPrimaryBroker();
+        messagesReceived = readAllMessages();
+        assertEquals(0, messagesReceived);
+    }
+
+    @Test(timeout = 60000)
+    public void testMessagesAreAckedAMQPProducer() throws Exception {
+        int messagesSent = 3;
+
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+        TextMessage message = null;
+        for (int i=0; i < messagesSent; i++) {
+            message = session.createTextMessage();
+            String messageText = "Hello " + i + " sent at " + new java.util.Date().toString();
+            message.setText(messageText);
+            LOG.debug(">>>> Sent [{}]", messageText);
+            producer.send(message);
+        }
+
+        connection.close();
+
+        // After the first restart we should get all messages sent above
+        restartPrimaryBroker();
+        int messagesReceived = readAllMessages();
+        assertEquals(messagesSent, messagesReceived);
+
+        // This time there should be no messages on this queue
+        restartPrimaryBroker();
+        messagesReceived = readAllMessages();
+        assertEquals(0, messagesReceived);
+    }
+
+    private int readAllMessages() throws Exception {
+        return readAllMessages(null);
+    }
+
+    private int readAllMessages(String selector) throws Exception {
+        Connection connection = createAmqpConnection();
+        connection.start();
+        try {
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            Queue queue = session.createQueue(name.getMethodName());
+            int messagesReceived = 0;
+            MessageConsumer consumer;
+
+            if (selector == null) {
+                consumer = session.createConsumer(queue);
+            } else {
+                consumer = session.createConsumer(queue, selector);
+            }
+
+            Message msg = consumer.receive(5000);
+            while (msg != null) {
+                assertNotNull(msg);
+                assertTrue(msg instanceof TextMessage);
+                TextMessage textMessage = (TextMessage) msg;
+                LOG.debug(">>>> Received [{}]", textMessage.getText());
+                messagesReceived++;
+                msg = consumer.receive(5000);
+            }
+
+            consumer.close();
+            return messagesReceived;
+        } finally {
+            connection.close();
+        }
+    }
+
+    @Test(timeout=30000)
+    public void testSelectors() throws Exception{
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer p = session.createProducer(queue);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+        p.send(message, DeliveryMode.PERSISTENT, 5, 0);
+
+        message = session.createTextMessage();
+        message.setText("hello + 9");
+        p.send(message, DeliveryMode.PERSISTENT, 9, 0);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(2, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue, "JMSPriority > 8");
+        Message msg = consumer.receive(5000);
+        assertNotNull(msg);
+        assertTrue(msg instanceof TextMessage);
+        assertEquals("hello + 9", ((TextMessage) msg).getText());
+        assertNull(consumer.receive(1000));
+    }
+
+    @Test(timeout=90000, expected=JMSSecurityException.class)
+    public void testConsumerNotAuthorized() throws Exception{
+        connection = createAmqpConnection("guest", "password");
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue("USERS." + name.getMethodName());
+        session.createConsumer(queue);
+    }
+
+    @Test(timeout=90000, expected=InvalidSelectorException.class)
+    public void testInvalidSelector() throws Exception{
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        session.createConsumer(queue, "3+5");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageGroupTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageGroupTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageGroupTest.java
new file mode 100644
index 0000000..395edfe
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsMessageGroupTest.java
@@ -0,0 +1,89 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JmsMessageGroupTest extends AmqpTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsMessageGroupTest.class);
+
+    @Ignore  // TODO - FIXME
+    @Test(timeout = 60000)
+    public void testGroupedMessagesDeliveredToOnlyOneConsumer() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer1 = session.createConsumer(queue);
+        MessageProducer producer = session.createProducer(queue);
+
+        // Send the messages.
+        for (int i = 0; i < 4; i++) {
+            TextMessage message = session.createTextMessage("message " + i);
+            message.setStringProperty("JMSXGroupID", "TEST-GROUP");
+            message.setIntProperty("JMSXGroupSeq", i + 1);
+            LOG.info("sending message: " + message);
+            producer.send(message);
+        }
+
+        // All the messages should have been sent down connection 1.. just get
+        // the first 3
+        for (int i = 0; i < 3; i++) {
+            TextMessage m1 = (TextMessage) consumer1.receive(500);
+            assertNotNull("m1 is null for index: " + i, m1);
+            assertEquals(m1.getIntProperty("JMSXGroupSeq"), i + 1);
+        }
+
+        // Setup a second connection
+        Connection connection1 = createAmqpConnection();
+        connection1.start();
+        Session session2 = connection1.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageConsumer consumer2 = session2.createConsumer(queue);
+
+        // Close the first consumer.
+        consumer1.close();
+
+        // The last messages should now go the the second consumer.
+        for (int i = 0; i < 1; i++) {
+            TextMessage m1 = (TextMessage) consumer2.receive(500);
+            assertNotNull("m1 is null for index: " + i, m1);
+            assertEquals(m1.getIntProperty("JMSXGroupSeq"), 4 + i);
+        }
+
+        // assert that there are no other messages left for the consumer 2
+        Message m = consumer2.receive(100);
+        assertNull("consumer 2 has some messages left", m);
+        connection1.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsQueueBrowserTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsQueueBrowserTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsQueueBrowserTest.java
new file mode 100644
index 0000000..dde6451
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsQueueBrowserTest.java
@@ -0,0 +1,140 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Enumeration;
+
+import javax.jms.Message;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test Basic Queue Browser implementation.
+ */
+public class JmsQueueBrowserTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsQueueBrowserTest.class);
+
+    @Test(timeout = 60000)
+    public void testCreateQueueBrowser() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        session.createConsumer(queue).close();
+
+        QueueBrowser browser = session.createBrowser(queue);
+        assertNotNull(browser);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test(timeout = 60000)
+    public void testNoMessagesBrowserHasNoElements() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        session.createConsumer(queue).close();
+
+        QueueBrowser browser = session.createBrowser(queue);
+        assertNotNull(browser);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+
+        Enumeration enumeration = browser.getEnumeration();
+        assertFalse(enumeration.hasMoreElements());
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test(timeout = 60000)
+    public void testBrowseAllInQueue() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        sendToAmqQueue(5);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(5, proxy.getQueueSize());
+
+        QueueBrowser browser = session.createBrowser(queue);
+        assertNotNull(browser);
+        Enumeration enumeration = browser.getEnumeration();
+        int count = 0;
+        while (enumeration.hasMoreElements()) {
+            Message msg = (Message) enumeration.nextElement();
+            assertNotNull(msg);
+            LOG.debug("Recv: {}", msg);
+            count++;
+        }
+        assertFalse(enumeration.hasMoreElements());
+        assertEquals(5, count);
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Test(timeout = 90000)
+    public void testBrowseAllInQueueSmallPrefetch() throws Exception {
+        connection = createAmqpConnection();
+        ((JmsConnection) connection).getPrefetchPolicy().setQueueBrowserPrefetch(10);
+        connection.start();
+
+        final int MSG_COUNT = 30;
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        sendToAmqQueue(MSG_COUNT);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(MSG_COUNT, proxy.getQueueSize());
+
+        QueueBrowser browser = session.createBrowser(queue);
+        assertNotNull(browser);
+        Enumeration enumeration = browser.getEnumeration();
+        int count = 0;
+        while (enumeration.hasMoreElements()) {
+            Message msg = (Message) enumeration.nextElement();
+            assertNotNull(msg);
+            LOG.debug("Recv: {}", msg);
+            count++;
+        }
+        assertFalse(enumeration.hasMoreElements());
+        assertEquals(MSG_COUNT, count);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsZeroPrefetchTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsZeroPrefetchTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsZeroPrefetchTest.java
new file mode 100644
index 0000000..eef250b
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsZeroPrefetchTest.java
@@ -0,0 +1,110 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JmsZeroPrefetchTest extends AmqpTestSupport {
+
+    @Test(timeout=60000, expected=JMSException.class)
+    public void testCannotUseMessageListener() throws Exception {
+        connection = createAmqpConnection();
+        ((JmsConnection)connection).getPrefetchPolicy().setAll(0);
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        MessageListener listener = new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+            }
+        };
+
+        consumer.setMessageListener(listener);
+    }
+
+    @Test(timeout = 60000)
+    public void testPullConsumerWorks() throws Exception {
+        connection = createAmqpConnection();
+        ((JmsConnection)connection).getPrefetchPolicy().setAll(0);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Hello World!"));
+
+        // now lets receive it
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message answer = consumer.receive(5000);
+        assertNotNull("Should have received a message!", answer);
+        // check if method will return at all and will return a null
+        answer = consumer.receive(1);
+        assertNull("Should have not received a message!", answer);
+        answer = consumer.receiveNoWait();
+        assertNull("Should have not received a message!", answer);
+    }
+
+    @Ignore // ActiveMQ doesn't honor link credit.
+    @Test(timeout = 60000)
+    public void testTwoConsumers() throws Exception {
+        connection = createAmqpConnection();
+        ((JmsConnection)connection).getPrefetchPolicy().setAll(0);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Msg1"));
+        producer.send(session.createTextMessage("Msg2"));
+
+        // now lets receive it
+        MessageConsumer consumer1 = session.createConsumer(queue);
+        MessageConsumer consumer2 = session.createConsumer(queue);
+        TextMessage answer = (TextMessage)consumer1.receive(5000);
+        assertNotNull(answer);
+        assertEquals("Should have received a message!", answer.getText(), "Msg1");
+        answer = (TextMessage)consumer2.receive(5000);
+        assertNotNull(answer);
+        assertEquals("Should have received a message!", answer.getText(), "Msg2");
+
+        answer = (TextMessage)consumer2.receiveNoWait();
+        assertNull("Should have not received a message!", answer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryQueueTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryQueueTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryQueueTest.java
new file mode 100644
index 0000000..1eccaf2
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryQueueTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.jms.destinations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.Session;
+import javax.jms.TemporaryQueue;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test functionality of Temporary Queues.
+ */
+public class JmsTemporaryQueueTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsTemporaryQueueTest.class);
+
+    @Test(timeout = 60000)
+    public void testCreateTemporaryQueue() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        TemporaryQueue queue = session.createTemporaryQueue();
+        session.createConsumer(queue);
+
+        assertEquals(1, brokerService.getAdminView().getTemporaryQueues().length);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryTopicTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryTopicTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryTopicTest.java
new file mode 100644
index 0000000..95e3303
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/destinations/JmsTemporaryTopicTest.java
@@ -0,0 +1,52 @@
+/**
+ * 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.jms.destinations;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.Session;
+import javax.jms.TemporaryTopic;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test functionality of Temporary Topics
+ */
+public class JmsTemporaryTopicTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsTemporaryTopicTest.class);
+
+    // Temp Topics not yet supported on the Broker.
+    @Ignore
+    @Test(timeout = 60000)
+    public void testCreateTemporaryTopic() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        TemporaryTopic topic = session.createTemporaryTopic();
+        session.createConsumer(topic);
+
+        assertEquals(1, brokerService.getAdminView().getTemporaryTopics().length);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsAmqpDiscoveryTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsAmqpDiscoveryTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsAmqpDiscoveryTest.java
new file mode 100644
index 0000000..77cf6ce
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsAmqpDiscoveryTest.java
@@ -0,0 +1,165 @@
+/**
+ * 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.jms.discovery;
+
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.JmsConnectionListener;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test that a Broker using AMQP can be discovered and JMS operations can be performed.
+ */
+public class JmsAmqpDiscoveryTest extends AmqpTestSupport implements JmsConnectionListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsAmqpDiscoveryTest.class);
+
+    private CountDownLatch interrupted;
+    private CountDownLatch restored;
+    private JmsConnection jmsConnection;
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        interrupted = new CountDownLatch(1);
+        restored = new CountDownLatch(1);
+    }
+
+    @Test(timeout=60000)
+    public void testRunningBrokerIsDiscovered() throws Exception {
+        connection = createConnection();
+        connection.start();
+
+        assertTrue("connection never connected.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return jmsConnection.isConnected();
+            }
+        }));
+    }
+
+    @Test(timeout=60000)
+    public void testConnectionFailsWhenBrokerGoesDown() throws Exception {
+        connection = createConnection();
+        connection.start();
+
+        assertTrue("connection never connected.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return jmsConnection.isConnected();
+            }
+        }));
+
+        LOG.info("Connection established, stopping broker.");
+        stopPrimaryBroker();
+
+        assertTrue("Interrupted event never fired", interrupted.await(30, TimeUnit.SECONDS));
+    }
+
+    @Test(timeout=60000)
+    public void testConnectionRestoresAfterBrokerRestarted() throws Exception {
+        connection = createConnection();
+        connection.start();
+
+        assertTrue("connection never connected.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return jmsConnection.isConnected();
+            }
+        }));
+
+        stopPrimaryBroker();
+        assertTrue(interrupted.await(20, TimeUnit.SECONDS));
+        startPrimaryBroker();
+        assertTrue(restored.await(20, TimeUnit.SECONDS));
+    }
+
+    @Test(timeout=60000)
+    public void testDiscoversAndReconnectsToSecondaryBroker() throws Exception {
+
+        connection = createConnection();
+        connection.start();
+
+        assertTrue("connection never connected.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return jmsConnection.isConnected();
+            }
+        }));
+
+        startNewBroker();
+        stopPrimaryBroker();
+
+        assertTrue(interrupted.await(20, TimeUnit.SECONDS));
+        assertTrue(restored.await(20, TimeUnit.SECONDS));
+    }
+
+    @Override
+    protected boolean isAmqpDiscovery() {
+        return true;
+    }
+
+    protected Connection createConnection() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(
+            "discovery:(multicast://default)?maxReconnectDelay=500");
+        connection = factory.createConnection();
+        jmsConnection = (JmsConnection) connection;
+        jmsConnection.addConnectionListener(this);
+        return connection;
+    }
+
+    @Override
+    public void onConnectionFailure(Throwable error) {
+        LOG.info("Connection reported failover: {}", error.getMessage());
+    }
+
+    @Override
+    public void onConnectionInterrupted(URI remoteURI) {
+        LOG.info("Connection reports interrupted. Lost connection to -> {}", remoteURI);
+        interrupted.countDown();
+    }
+
+    @Override
+    public void onConnectionRestored(URI remoteURI) {
+        LOG.info("Connection reports restored.  Connected to -> {}", remoteURI);
+        restored.countDown();
+    }
+
+    @Override
+    public void onMessage(JmsInboundMessageDispatch envelope) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsDiscoveryProviderTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsDiscoveryProviderTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsDiscoveryProviderTest.java
new file mode 100644
index 0000000..3d53957
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/discovery/JmsDiscoveryProviderTest.java
@@ -0,0 +1,107 @@
+/**
+ * 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.jms.discovery;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.qpid.jms.provider.DefaultProviderListener;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.discovery.DiscoveryProviderFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Test basic discovery of remote brokers
+ */
+public class JmsDiscoveryProviderTest {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsDiscoveryProviderTest.class);
+
+    @Rule public TestName name = new TestName();
+
+    private BrokerService broker;
+
+    @Before
+    public void setup() throws Exception {
+        broker = createBroker();
+        broker.start();
+        broker.waitUntilStarted();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (broker != null) {
+            broker.stop();
+            broker.waitUntilStopped();
+            broker = null;
+        }
+    }
+
+    @Test(timeout=30000)
+    public void testCreateDiscvoeryProvider() throws Exception {
+        URI discoveryUri = new URI("discovery:multicast://default");
+        Provider provider = DiscoveryProviderFactory.createAsync(discoveryUri);
+        assertNotNull(provider);
+
+        DefaultProviderListener listener = new DefaultProviderListener();
+        provider.setProviderListener(listener);
+        provider.start();
+        provider.close();
+    }
+
+    @Test(timeout=30000, expected=IllegalStateException.class)
+    public void testStartFailsWithNoListener() throws Exception {
+        URI discoveryUri = new URI("discovery:multicast://default");
+        Provider provider =
+            DiscoveryProviderFactory.createAsync(discoveryUri);
+        assertNotNull(provider);
+        provider.start();
+        provider.close();
+    }
+
+    @Test(timeout=30000, expected=IOException.class)
+    public void testCreateFailsWithUnknownAgent() throws Exception {
+        URI discoveryUri = new URI("discovery:unknown://default");
+        Provider provider = DiscoveryProviderFactory.createAsync(discoveryUri);
+        provider.close();
+    }
+
+    protected BrokerService createBroker() throws Exception {
+
+        BrokerService brokerService = new BrokerService();
+        brokerService.setBrokerName("localhost");
+        brokerService.setPersistent(false);
+        brokerService.setAdvisorySupport(false);
+        brokerService.setUseJmx(false);
+
+        TransportConnector connector = brokerService.addConnector("amqp://0.0.0.0:0");
+        connector.setName("amqp");
+        connector.setDiscoveryUri(new URI("multicast://default"));
+
+        return brokerService;
+    }
+}


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


[22/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessage.java
new file mode 100644
index 0000000..8bee2e3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessage.java
@@ -0,0 +1,643 @@
+/**
+ * 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.jms.message;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsMessageId;
+import org.apache.qpid.jms.util.TypeConversionSupport;
+
+public class JmsMessage implements javax.jms.Message {
+
+    protected transient Callable<Void> acknowledgeCallback;
+    protected transient JmsConnection connection;
+
+    protected final JmsMessageFacade facade;
+    protected boolean readOnlyBody;
+    protected boolean readOnlyProperties;
+
+    public JmsMessage(JmsMessageFacade facade) {
+        this.facade = facade;
+    }
+
+    public JmsMessage copy() throws JMSException {
+        JmsMessage other = new JmsMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    protected void copy(JmsMessage other) {
+        this.readOnlyBody = other.readOnlyBody;
+        this.readOnlyProperties = other.readOnlyBody;
+        this.acknowledgeCallback = other.acknowledgeCallback;
+        this.connection = other.connection;
+    }
+
+    @Override
+    public int hashCode() {
+        String id = null;
+        try {
+            id = getJMSMessageID();
+        } catch (JMSException e) {
+        }
+
+        if (id != null) {
+            return id.hashCode();
+        } else {
+            return super.hashCode();
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || o.getClass() != getClass()) {
+            return false;
+        }
+
+        JmsMessage msg = (JmsMessage) o;
+        JmsMessageId oMsg = null;
+        JmsMessageId thisMsg = null;
+
+        thisMsg = facade.getMessageId();
+        oMsg = msg.facade.getMessageId();
+
+        return thisMsg != null && oMsg != null && oMsg.equals(thisMsg);
+    }
+
+    @Override
+    public void acknowledge() throws JMSException {
+        if (acknowledgeCallback != null) {
+            try {
+                acknowledgeCallback.call();
+            } catch (Throwable e) {
+                throw JmsExceptionSupport.create(e);
+            }
+        }
+    }
+
+    @Override
+    public void clearBody() throws JMSException {
+        readOnlyBody = false;
+        facade.clearBody();
+    }
+
+    public boolean isReadOnlyBody() {
+        return this.readOnlyBody;
+    }
+
+    public void setReadOnlyBody(boolean readOnlyBody) {
+        this.readOnlyBody = readOnlyBody;
+    }
+
+    public void setReadOnlyProperties(boolean readOnlyProperties) {
+        this.readOnlyProperties = readOnlyProperties;
+    }
+
+    @Override
+    public String getJMSMessageID() throws JMSException {
+        if (facade.getMessageId() == null) {
+            return null;
+        }
+        return facade.getMessageId().toString();
+    }
+
+    @Override
+    public void setJMSMessageID(String value) throws JMSException {
+        if (value != null) {
+            JmsMessageId id = new JmsMessageId(value);
+            facade.setMessageId(id);
+        } else {
+            facade.setMessageId(null);
+        }
+    }
+
+    public void setJMSMessageID(JmsMessageId messageId) throws JMSException {
+        facade.setMessageId(messageId);
+    }
+
+    @Override
+    public long getJMSTimestamp() throws JMSException {
+        return facade.getTimestamp();
+    }
+
+    @Override
+    public void setJMSTimestamp(long timestamp) throws JMSException {
+        facade.setTimestamp(timestamp);
+    }
+
+    @Override
+    public String getJMSCorrelationID() throws JMSException {
+        return facade.getCorrelationId();
+    }
+
+    @Override
+    public void setJMSCorrelationID(String correlationId) throws JMSException {
+        facade.setCorrelationId(correlationId);
+    }
+
+    @Override
+    public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
+        return facade.getCorrelationIdBytes();
+    }
+
+    @Override
+    public void setJMSCorrelationIDAsBytes(byte[] correlationId) throws JMSException {
+        facade.setCorrelationIdBytes(correlationId);
+    }
+
+    @Override
+    public Destination getJMSReplyTo() throws JMSException {
+        return facade.getReplyTo();
+    }
+
+    @Override
+    public void setJMSReplyTo(Destination destination) throws JMSException {
+        facade.setReplyTo(JmsMessageTransformation.transformDestination(connection, destination));
+    }
+
+    @Override
+    public Destination getJMSDestination() throws JMSException {
+        return facade.getDestination();
+    }
+
+    @Override
+    public void setJMSDestination(Destination destination) throws JMSException {
+        facade.setDestination(JmsMessageTransformation.transformDestination(connection, destination));
+    }
+
+    @Override
+    public int getJMSDeliveryMode() throws JMSException {
+        return facade.isPersistent() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT;
+    }
+
+    @Override
+    public void setJMSDeliveryMode(int mode) throws JMSException {
+        facade.setPersistent(mode == DeliveryMode.PERSISTENT);
+    }
+
+    @Override
+    public boolean getJMSRedelivered() throws JMSException {
+        return this.isRedelivered();
+    }
+
+    @Override
+    public void setJMSRedelivered(boolean redelivered) throws JMSException {
+        this.setRedelivered(redelivered);
+    }
+
+    @Override
+    public String getJMSType() throws JMSException {
+        return facade.getType();
+    }
+
+    @Override
+    public void setJMSType(String type) throws JMSException {
+        facade.setType(type);
+    }
+
+    @Override
+    public long getJMSExpiration() throws JMSException {
+        return facade.getExpiration();
+    }
+
+    @Override
+    public void setJMSExpiration(long expiration) throws JMSException {
+        facade.setExpiration(expiration);
+    }
+
+    @Override
+    public int getJMSPriority() throws JMSException {
+        return facade.getPriority();
+    }
+
+    @Override
+    public void setJMSPriority(int priority) throws JMSException {
+        byte scaled = 0;
+
+        if (priority < 0) {
+            scaled = 0;
+        } else if (priority > 9) {
+            scaled = 9;
+        } else {
+            scaled = (byte) priority;
+        }
+
+        facade.setPriority(scaled);
+    }
+
+    @Override
+    public void clearProperties() throws JMSException {
+        facade.clearProperties();
+    }
+
+    @Override
+    public boolean propertyExists(String name) throws JMSException {
+        return JmsMessagePropertyIntercepter.propertyExists(facade, name);
+    }
+
+    /**
+     * Returns an unmodifiable Map containing the properties contained within the message.
+     *
+     * @return unmodifiable Map of the current properties in the message.
+     *
+     * @throws JMSException if there is an error accessing the message properties.
+     */
+    public Map<String, Object> getProperties() throws JMSException {
+        return Collections.unmodifiableMap(facade.getProperties());
+    }
+
+    /**
+     * Allows for a direct put of an Object value into the message properties.
+     *
+     * This method bypasses the normal JMS type checking for properties being set on
+     * the message and should be used with great care.
+     *
+     * @param key
+     *        the property name to use when setting the value.
+     * @param value
+     *        the value to insert into the message properties.
+     *
+     * @throws JMSException if an error occurs while accessing the Message properties.
+     */
+    public void setProperty(String key, Object value) throws JMSException {
+        this.facade.setProperty(key, value);
+    }
+
+    /**
+     * Returns the Object value referenced by the given key.
+     *
+     * @param key
+     *        the name of the property being accessed.
+     *
+     * @return the value stored at the given location or null if non set.
+     *
+     * @throws JMSException if an error occurs while accessing the Message properties.
+     */
+    public Object getProperty(String key) throws JMSException {
+        return this.facade.getProperty(key);
+    }
+
+    @Override
+    public Enumeration<?> getPropertyNames() throws JMSException {
+        Set<String> result = new HashSet<String>(facade.getProperties().keySet());
+        return Collections.enumeration(result);
+    }
+
+    /**
+     * return all property names, including standard JMS properties and JMSX
+     * properties
+     *
+     * @return Enumeration of all property names on this message
+     * @throws JMSException
+     */
+    public Enumeration<?> getAllPropertyNames() throws JMSException {
+        Set<String> result = new HashSet<String>(facade.getProperties().keySet());
+        result.addAll(JmsMessagePropertyIntercepter.getAllPropertyNames());
+        return Collections.enumeration(result);
+    }
+
+    @Override
+    public void setObjectProperty(String name, Object value) throws JMSException {
+        checkReadOnlyProperties();
+        checkPropertyNameIsValid(name);
+        checkValidObject(value);
+        JmsMessagePropertyIntercepter.setProperty(facade, name, value);
+    }
+
+    public void setProperties(Map<String, Object> properties) throws JMSException {
+        for (Iterator<Map.Entry<String, Object>> iter = properties.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry<String, Object> entry = iter.next();
+            setObjectProperty(entry.getKey(), entry.getValue());
+        }
+    }
+
+    protected void checkValidObject(Object value) throws MessageFormatException {
+        boolean valid = value instanceof Boolean ||
+                        value instanceof Byte ||
+                        value instanceof Short ||
+                        value instanceof Integer ||
+                        value instanceof Long ||
+                        value instanceof Float ||
+                        value instanceof Double ||
+                        value instanceof Character ||
+                        value instanceof String ||
+                        value == null;
+
+        if (!valid) {
+            throw new MessageFormatException("Only objectified primitive objects and String types are allowed but was: " + value + " type: " + value.getClass());
+        }
+    }
+
+    @Override
+    public Object getObjectProperty(String name) throws JMSException {
+        if (name == null) {
+            throw new NullPointerException("Property name cannot be null");
+        }
+
+        return JmsMessagePropertyIntercepter.getProperty(facade, name);
+    }
+
+    @Override
+    public boolean getBooleanProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            return false;
+        }
+        Boolean rc = (Boolean) TypeConversionSupport.convert(value, Boolean.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a boolean");
+        }
+        return rc.booleanValue();
+    }
+
+    @Override
+    public byte getByteProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            throw new NumberFormatException("property " + name + " was null");
+        }
+        Byte rc = (Byte) TypeConversionSupport.convert(value, Byte.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a byte");
+        }
+        return rc.byteValue();
+    }
+
+    @Override
+    public short getShortProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            throw new NumberFormatException("property " + name + " was null");
+        }
+        Short rc = (Short) TypeConversionSupport.convert(value, Short.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a short");
+        }
+        return rc.shortValue();
+    }
+
+    @Override
+    public int getIntProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            throw new NumberFormatException("property " + name + " was null");
+        }
+        Integer rc = (Integer) TypeConversionSupport.convert(value, Integer.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as an integer");
+        }
+        return rc.intValue();
+    }
+
+    @Override
+    public long getLongProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            throw new NumberFormatException("property " + name + " was null");
+        }
+        Long rc = (Long) TypeConversionSupport.convert(value, Long.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a long");
+        }
+        return rc.longValue();
+    }
+
+    @Override
+    public float getFloatProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            throw new NullPointerException("property " + name + " was null");
+        }
+        Float rc = (Float) TypeConversionSupport.convert(value, Float.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a float");
+        }
+        return rc.floatValue();
+    }
+
+    @Override
+    public double getDoubleProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            throw new NullPointerException("property " + name + " was null");
+        }
+        Double rc = (Double) TypeConversionSupport.convert(value, Double.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a double");
+        }
+        return rc.doubleValue();
+    }
+
+    @Override
+    public String getStringProperty(String name) throws JMSException {
+        Object value = getObjectProperty(name);
+        if (value == null) {
+            return null;
+        }
+        String rc = (String) TypeConversionSupport.convert(value, String.class);
+        if (rc == null) {
+            throw new MessageFormatException("Property " + name + " was a " + value.getClass().getName() + " and cannot be read as a String");
+        }
+        return rc;
+    }
+
+    @Override
+    public void setBooleanProperty(String name, boolean value) throws JMSException {
+        setObjectProperty(name, Boolean.valueOf(value));
+    }
+
+    @Override
+    public void setByteProperty(String name, byte value) throws JMSException {
+        setObjectProperty(name, Byte.valueOf(value));
+    }
+
+    @Override
+    public void setShortProperty(String name, short value) throws JMSException {
+        setObjectProperty(name, Short.valueOf(value));
+    }
+
+    @Override
+    public void setIntProperty(String name, int value) throws JMSException {
+        setObjectProperty(name, Integer.valueOf(value));
+    }
+
+    @Override
+    public void setLongProperty(String name, long value) throws JMSException {
+        setObjectProperty(name, Long.valueOf(value));
+    }
+
+    @Override
+    public void setFloatProperty(String name, float value) throws JMSException {
+        setObjectProperty(name, new Float(value));
+    }
+
+    @Override
+    public void setDoubleProperty(String name, double value) throws JMSException {
+        setObjectProperty(name, new Double(value));
+    }
+
+    @Override
+    public void setStringProperty(String name, String value) throws JMSException {
+        setObjectProperty(name, value);
+    }
+
+    public Callable<Void> getAcknowledgeCallback() {
+        return acknowledgeCallback;
+    }
+
+    public void setAcknowledgeCallback(Callable<Void> acknowledgeCallback) {
+        this.acknowledgeCallback = acknowledgeCallback;
+    }
+
+    /**
+     * Send operation event listener. Used to get the message ready to be sent.
+     *
+     * @throws JMSException
+     */
+    public void onSend() throws JMSException {
+        setReadOnlyBody(true);
+        setReadOnlyProperties(true);
+        facade.onSend();
+    }
+
+    public JmsConnection getConnection() {
+        return connection;
+    }
+
+    public void setConnection(JmsConnection connection) {
+        this.connection = connection;
+    }
+
+    public boolean isExpired() throws JMSException {
+        long expireTime = facade.getExpiration();
+        return expireTime > 0 && System.currentTimeMillis() > expireTime;
+    }
+
+    public void incrementRedeliveryCount() {
+         facade.setRedeliveryCounter(facade.getRedeliveryCounter() + 1);
+    }
+
+    public JmsMessageFacade getFacade() {
+        return this.facade;
+    }
+
+    public boolean isRedelivered() throws JMSException {
+        return facade.isRedelivered();
+    }
+
+    public void setRedelivered(boolean redelivered) throws JMSException {
+        if (redelivered) {
+            if (!isRedelivered()) {
+                facade.setRedeliveryCounter(1);
+            }
+        } else {
+            if (isRedelivered()) {
+                facade.setRedeliveryCounter(0);
+            }
+        }
+    }
+
+    protected void checkReadOnlyProperties() throws MessageNotWriteableException {
+        if (readOnlyProperties) {
+            throw new MessageNotWriteableException("Message properties are read-only");
+        }
+    }
+
+    protected void checkReadOnlyBody() throws MessageNotWriteableException {
+        if (readOnlyBody) {
+            throw new MessageNotWriteableException("Message body is read-only");
+        }
+    }
+
+    protected void checkWriteOnlyBody() throws MessageNotReadableException {
+        if (!readOnlyBody) {
+            throw new MessageNotReadableException("Message body is write-only");
+        }
+    }
+
+    private void checkPropertyNameIsValid(String propertyName) throws IllegalArgumentException {
+        if (propertyName == null) {
+            throw new IllegalArgumentException("Property name must not be null");
+        } else if (propertyName.length() == 0) {
+            throw new IllegalArgumentException("Property name must not be the empty string");
+        }
+
+        checkIdentifierFormat(propertyName);
+    }
+
+    private void checkIdentifierFormat(String identifier) throws IllegalArgumentException {
+        checkIdentifierLetterAndDigitRequirements(identifier);
+        checkIdentifierIsntNullTrueFalse(identifier);
+        checkIdentifierIsntLogicOperator(identifier);
+    }
+
+    private void checkIdentifierIsntLogicOperator(String identifier) {
+        // Identifiers cannot be NOT, AND, OR, BETWEEN, LIKE, IN, IS, or ESCAPE.
+        if ("NOT".equals(identifier) || "AND".equals(identifier) || "OR".equals(identifier) ||
+            "BETWEEN".equals(identifier) || "LIKE".equals(identifier) || "IN".equals(identifier) ||
+            "IS".equals(identifier) || "ESCAPE".equals(identifier)) {
+
+            throw new IllegalArgumentException("Identifier not allowed in JMS: '" + identifier + "'");
+        }
+    }
+
+    private void checkIdentifierIsntNullTrueFalse(String identifier) {
+        // Identifiers cannot be the names NULL, TRUE, and FALSE.
+        if ("NULL".equals(identifier) || "TRUE".equals(identifier) || "FALSE".equals(identifier)) {
+            throw new IllegalArgumentException("Identifier not allowed in JMS: '" + identifier + "'");
+        }
+    }
+
+    private void checkIdentifierLetterAndDigitRequirements(String identifier) {
+        // An identifier is an unlimited-length sequence of letters and digits, the first of
+        // which must be a letter.  A letter is any character for which the method
+        // Character.isJavaLetter returns true.  This includes '_' and '$'.  A letter or digit
+        // is any character for which the method Character.isJavaLetterOrDigit returns true.
+        char startChar = identifier.charAt(0);
+        if (!(Character.isJavaIdentifierStart(startChar))) {
+            throw new IllegalArgumentException("Identifier does not begin with a valid JMS identifier start character: '" + identifier + "' ");
+        }
+
+        // JMS part character
+        int length = identifier.length();
+        for (int i = 1; i < length; i++) {
+            char ch = identifier.charAt(i);
+            if (!(Character.isJavaIdentifierPart(ch))) {
+                throw new IllegalArgumentException("Identifier contains invalid JMS identifier character '" + ch + "': '" + identifier + "' ");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageFactory.java
new file mode 100644
index 0000000..91c148c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageFactory.java
@@ -0,0 +1,133 @@
+/**
+ * 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.jms.message;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
+/**
+ * Interface that a Provider should implement to provide a Provider
+ * Specific JmsMessage implementation that optimizes the exchange of
+ * message properties and payload between the JMS Message API and the
+ * underlying Provider Message implementations.
+ */
+public interface JmsMessageFactory {
+
+    /**
+     * Creates an instance of a basic JmsMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @return a newly created and initialized JmsMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsMessage createMessage() throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsTextMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @param payload
+     *        The value to initially assign to the Message body, or null if empty to start.
+     *
+     * @returns a newly created and initialized JmsTextMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsTextMessage createTextMessage(String payload) throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsTextMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @returns a newly created and initialized JmsTextMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsTextMessage createTextMessage() throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsBytesMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @returns a newly created and initialized JmsTextMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsBytesMessage createBytesMessage() throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsMapMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @returns a newly created and initialized JmsTextMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsMapMessage createMapMessage() throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsStreamMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @returns a newly created and initialized JmsTextMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsStreamMessage createStreamMessage() throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsObjectMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @param payload
+     *        The value to initially assign to the Message body, or null if empty to start.
+     *
+     * @returns a newly created and initialized JmsObjectMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsObjectMessage createObjectMessage(Serializable payload) throws JMSException;
+
+    /**
+     * Creates an instance of a basic JmsObjectMessage object.  The provider may
+     * either create the Message with the default generic internal message
+     * implementation or create a Provider specific instance that optimizes
+     * the access and marshaling of the message.
+     *
+     * @returns a newly created and initialized JmsObjectMessage instance.
+     *
+     * @throws JMSException if the provider cannot create the message for some reason.
+     */
+    JmsObjectMessage createObjectMessage() throws JMSException;
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessagePropertyIntercepter.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessagePropertyIntercepter.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessagePropertyIntercepter.java
new file mode 100644
index 0000000..863f420
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessagePropertyIntercepter.java
@@ -0,0 +1,622 @@
+/**
+ * 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.jms.message;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsMessageId;
+import org.apache.qpid.jms.util.TypeConversionSupport;
+
+/**
+ * Utility class used to intercept calls to Message property gets and sets and map the
+ * correct fields in the underlying JmsMessageFacade to the property name being operated on.
+ */
+public class JmsMessagePropertyIntercepter {
+
+    private static final Map<String, PropertyIntercepter> PROPERTY_INTERCEPTERS =
+        new HashMap<String, PropertyIntercepter>();
+
+    /**
+     * Interface for a Property intercepter object used to write JMS style
+     * properties that are part of the JMS Message object members or perform
+     * some needed conversion action before some named property is read or
+     * written.  If a property is not writable then the intercepter should
+     * throw an JMSException to indicate the error.
+     */
+    interface PropertyIntercepter {
+
+        /**
+         * Called when the names property is queried from an JMS Message object.
+         *
+         * @param message
+         *        The message being acted upon.
+         *
+         * @return the correct property value from the given Message.
+         *
+         * @throws JMSException if an error occurs while accessing the property
+         */
+        Object getProperty(JmsMessageFacade message) throws JMSException;
+
+        /**
+         * Called when the names property is assigned from an JMS Message object.
+         *
+         * @param message
+         *        The message instance being acted upon.
+         * @param value
+         *        The value to assign to the intercepted property.
+         *
+         * @throws JMSException if an error occurs writing the property.
+         */
+        void setProperty(JmsMessageFacade message, Object value) throws JMSException;
+
+        /**
+         * Indicates if the intercepted property has a value currently assigned.
+         *
+         * @param message
+         *        The message instance being acted upon.
+         *
+         * @return true if the intercepted property has a value assigned to it.
+         */
+        boolean propertyExists(JmsMessageFacade message);
+
+    }
+
+    static {
+        PROPERTY_INTERCEPTERS.put("JMSXDeliveryCount", new PropertyIntercepter() {
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Integer rc = (Integer) TypeConversionSupport.convert(value, Integer.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSXDeliveryCount cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setRedeliveryCounter(rc.intValue() - 1);
+            }
+
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return Integer.valueOf(message.getRedeliveryCounter() + 1);
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSDestination", new PropertyIntercepter() {
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                JmsDestination rc = (JmsDestination) TypeConversionSupport.convert(value, JmsDestination.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSDestination cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setDestination(rc);
+            }
+
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                Destination dest = message.getDestination();
+                if (dest == null) {
+                    return null;
+                }
+                return dest.toString();
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getDestination() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSReplyTo", new PropertyIntercepter() {
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                JmsDestination rc = (JmsDestination) TypeConversionSupport.convert(value, JmsDestination.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSReplyTo cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setReplyTo(rc);
+            }
+
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                if (message.getReplyTo() == null) {
+                    return null;
+                }
+                return message.getReplyTo().toString();
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getReplyTo() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSType", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return message.getType();
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                String rc = (String) TypeConversionSupport.convert(value, String.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSType cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setType(rc);
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getType() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSDeliveryMode", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return message.isPersistent() ? "PERSISTENT" : "NON_PERSISTENT";
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Integer rc = null;
+                try {
+                    rc = (Integer) TypeConversionSupport.convert(value, Integer.class);
+                } catch (NumberFormatException nfe) {
+                    if (value instanceof String) {
+                        if (((String) value).equalsIgnoreCase("PERSISTENT")) {
+                            rc = DeliveryMode.PERSISTENT;
+                        } else if (((String) value).equalsIgnoreCase("NON_PERSISTENT")) {
+                            rc = DeliveryMode.NON_PERSISTENT;
+                        } else {
+                            throw nfe;
+                        }
+                    }
+                }
+                if (rc == null) {
+                    Boolean bool = (Boolean) TypeConversionSupport.convert(value, Boolean.class);
+                    if (bool == null) {
+                        throw new JMSException("Property JMSDeliveryMode cannot be set from a " + value.getClass().getName() + ".");
+                    } else {
+                        message.setPersistent(bool.booleanValue());
+                    }
+                } else {
+                    message.setPersistent(rc == DeliveryMode.PERSISTENT);
+                }
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSPriority", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return Integer.valueOf(message.getPriority());
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Integer rc = (Integer) TypeConversionSupport.convert(value, Integer.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSPriority cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setPriority(rc.byteValue());
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSMessageID", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                if (message.getMessageId() == null) {
+                    return null;
+                }
+                return message.getMessageId().toString();
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                String rc = (String) TypeConversionSupport.convert(value, String.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSMessageID cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setMessageId(new JmsMessageId(rc));
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getMessageId() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSTimestamp", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return Long.valueOf(message.getTimestamp());
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Long rc = (Long) TypeConversionSupport.convert(value, Long.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSTimestamp cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setTimestamp(rc.longValue());
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSCorrelationID", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return message.getCorrelationId();
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                String rc = (String) TypeConversionSupport.convert(value, String.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSCorrelationID cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setCorrelationId(rc);
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getCorrelationId() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSExpiration", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return Long.valueOf(message.getExpiration());
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Long rc = (Long) TypeConversionSupport.convert(value, Long.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSExpiration cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setExpiration(rc.longValue());
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSRedelivered", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return Boolean.valueOf(message.isRedelivered());
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Boolean rc = (Boolean) TypeConversionSupport.convert(value, Boolean.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSRedelivered cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setRedelivered(rc.booleanValue());
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSXGroupID", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return message.getGroupId();
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                String rc = (String) TypeConversionSupport.convert(value, String.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSXGroupID cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setGroupId(rc);
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getGroupId() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSXGroupSeq", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                return message.getGroupSequence();
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                Integer rc = (Integer) TypeConversionSupport.convert(value, Integer.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSXGroupSeq cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setGroupSequence(rc.intValue());
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return true;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put("JMSXUserID", new PropertyIntercepter() {
+            @Override
+            public Object getProperty(JmsMessageFacade message) throws JMSException {
+                Object userId = message.getUserId();
+                if (userId == null) {
+                    try {
+                        userId = message.getProperty("JMSXUserID");
+                    } catch (Exception e) {
+                        throw JmsExceptionSupport.create(e);
+                    }
+                }
+
+                return userId;
+            }
+
+            @Override
+            public void setProperty(JmsMessageFacade message, Object value) throws JMSException {
+                String rc = (String) TypeConversionSupport.convert(value, String.class);
+                if (rc == null) {
+                    throw new JMSException("Property JMSXUserID cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setUserId(rc);
+            }
+
+            @Override
+            public boolean propertyExists(JmsMessageFacade message) {
+                return message.getUserId() != null;
+            }
+        });
+    }
+
+    /**
+     * Static get method that takes a property name and gets the value either via
+     * a registered property get object or through the JmsMessageFacade getProperty
+     * method.
+     *
+     * @param message
+     *        the JmsMessageFacade instance to read from
+     * @param name
+     *        the property name that is being requested.
+     *
+     * @return the correct value either mapped to an Message attribute of a Message property.
+     *
+     * @throws JMSException if an error occurs while reading the defined property.
+     */
+    public static Object getProperty(JmsMessageFacade message, String name) throws JMSException {
+        Object value = null;
+
+        PropertyIntercepter jmsPropertyExpression = PROPERTY_INTERCEPTERS.get(name);
+        if (jmsPropertyExpression != null) {
+            value = jmsPropertyExpression.getProperty(message);
+        } else {
+            value = message.getProperty(name);
+        }
+
+        return value;
+    }
+
+    /**
+     * Static set method that takes a property name and sets the value either via
+     * a registered property set object or through the JmsMessageFacade setProperty
+     * method.
+     *
+     * @param message
+     *        the JmsMessageFacade instance to write to.
+     * @param name
+     *        the property name that is being written.
+     * @param value
+     *        the new value to assign for the named property.
+     *
+     * @throws JMSException if an error occurs while writing the defined property.
+     */
+    public static void setProperty(JmsMessageFacade message, String name, Object value) throws JMSException {
+        PropertyIntercepter jmsPropertyExpression = PROPERTY_INTERCEPTERS.get(name);
+        if (jmsPropertyExpression != null) {
+            jmsPropertyExpression.setProperty(message, value);
+        } else {
+            message.setProperty(name, value);
+        }
+    }
+
+    /**
+     * Static inspection method to determine if a named property exists for a given message.
+     *
+     * @param message
+     *        the JmsMessageFacade instance to read from
+     * @param name
+     *        the property name that is being inspected.
+     *
+     * @return true if the message contains the given property.
+     *
+     * @throws JMSException if an error occurs while validating the defined property.
+     */
+    public static boolean propertyExists(JmsMessageFacade message, String name) throws JMSException {
+        PropertyIntercepter jmsPropertyExpression = PROPERTY_INTERCEPTERS.get(name);
+        if (jmsPropertyExpression != null) {
+            return jmsPropertyExpression.propertyExists(message);
+        } else {
+            return message.propertyExists(name);
+        }
+    }
+
+    /**
+     * For each of the currently configured message property intercepter instance a
+     * string key value is inserted into an Set and returned.
+     *
+     * @return a Set<String> containing the names of all intercepted properties.
+     */
+    public static Set<String> getAllPropertyNames() {
+        return PROPERTY_INTERCEPTERS.keySet();
+    }
+
+    /**
+     * For each of the currently configured message property intercepter instance a
+     * string key value is inserted into an Set and returned if the property has a
+     * value and is available for a read operation.
+     *
+     * @return a Set<String> containing the names of all intercepted properties with a value.
+     */
+    public static Set<String> getPropertyNames(JmsMessageFacade message) {
+        Set<String> names = new HashSet<String>();
+        for (Entry<String, PropertyIntercepter> entry : PROPERTY_INTERCEPTERS.entrySet()) {
+            if (entry.getValue().propertyExists(message)) {
+                names.add(entry.getKey());
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Allows for the additional PropertyIntercepter instances to be added to the global set.
+     *
+     * @param propertyName
+     *        The name of the Message property that will be intercepted.
+     * @param getter
+     *        The PropertyIntercepter instance that should be used for the named property.
+     */
+    public static void addPropertySetter(String propertyName, PropertyIntercepter getter) {
+        PROPERTY_INTERCEPTERS.put(propertyName, getter);
+    }
+
+    /**
+     * Given a property name, remove the configured intercepter that has been assigned to
+     * intercept the queries for that property value.
+     *
+     * @param propertyName
+     *        The name of the PropertyIntercepter to remove.
+     *
+     * @return true if a getter was removed from the global set.
+     */
+    public boolean removePropertySetter(String propertyName) {
+        if (PROPERTY_INTERCEPTERS.remove(propertyName) != null) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private final String name;
+    private final PropertyIntercepter jmsPropertyExpression;
+
+    /**
+     * Creates an new property getter instance that is assigned to read the named value.
+     *
+     * @param name
+     *        the property value that this getter is assigned to lookup.
+     */
+    public JmsMessagePropertyIntercepter(String name) {
+        this.name = name;
+        this.jmsPropertyExpression = PROPERTY_INTERCEPTERS.get(name);
+    }
+
+    /**
+     * Gets the correct property value from the JmsMessageFacade instance based on
+     * the predefined property mappings.
+     *
+     * @param message
+     *        the JmsMessageFacade whose property is being read.
+     *
+     * @return the correct value either mapped to an Message attribute of a Message property.
+     *
+     * @throws JMSException if an error occurs while reading the defined property.
+     */
+    public Object get(JmsMessageFacade message) throws JMSException {
+        if (jmsPropertyExpression != null) {
+            return jmsPropertyExpression.getProperty(message);
+        }
+
+        return message.getProperty(name);
+    }
+
+    /**
+     * Sets the correct property value from the JmsMessageFacade instance based on
+     * the predefined property mappings.
+     *
+     * @param message
+     *        the JmsMessageFacade whose property is being read.
+     * @param value
+     *        the value to be set on the intercepted JmsMessageFacade property.
+     *
+     * @throws JMSException if an error occurs while reading the defined property.
+     */
+    public void set(JmsMessageFacade message, Object value) throws JMSException {
+        if (jmsPropertyExpression != null) {
+            jmsPropertyExpression.setProperty(message, value);
+        } else {
+            message.setProperty(name, value);
+        }
+    }
+
+    /**
+     * @return the property name that is being intercepted for the JmsMessageFacade.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !this.getClass().equals(o.getClass())) {
+            return false;
+        }
+        return name.equals(((JmsMessagePropertyIntercepter) o).name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageTransformation.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageTransformation.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageTransformation.java
new file mode 100644
index 0000000..404cabd
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMessageTransformation.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.jms.message;
+
+import java.util.Enumeration;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageEOFException;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.JmsTemporaryQueue;
+import org.apache.qpid.jms.JmsTemporaryTopic;
+import org.apache.qpid.jms.JmsTopic;
+
+/**
+ * A helper class for converting normal JMS interfaces into the QpidJMS specific
+ * versions.
+ */
+public final class JmsMessageTransformation {
+
+    private JmsMessageTransformation() {
+    }
+
+    /**
+     * Creates a an available JMS message from another provider.
+     *
+     * @param destination
+     *        - Destination to be converted into Jms's implementation.
+     * @return JmsDestination - Jms's implementation of the
+     *         destination.
+     * @throws JMSException
+     * @throws JMSException
+     *         if an error occurs
+     */
+    public static JmsDestination transformDestination(JmsConnection connection, Destination destination) throws JMSException {
+        JmsDestination result = null;
+
+        if (destination != null) {
+            if (destination instanceof JmsDestination) {
+                return (JmsDestination) destination;
+
+            } else {
+                if (destination instanceof TemporaryQueue) {
+                    result = new JmsTemporaryQueue(((TemporaryQueue) destination).getQueueName());
+                } else if (destination instanceof TemporaryTopic) {
+                    result = new JmsTemporaryTopic(((TemporaryTopic) destination).getTopicName());
+                } else if (destination instanceof Queue) {
+                    result = new JmsQueue(((Queue) destination).getQueueName());
+                } else if (destination instanceof Topic) {
+                    result = new JmsTopic(((Topic) destination).getTopicName());
+                }
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Creates a fast shallow copy of the current JmsMessage or creates a
+     * whole new message instance from an available JMS message from another
+     * provider.
+     *
+     * @param message
+     *        - Message to be converted into Jms's implementation.
+     * @param connection
+     * @return JmsMessage - Jms's implementation object of the
+     *         message.
+     * @throws JMSException
+     *         if an error occurs
+     */
+    public static JmsMessage transformMessage(JmsConnection connection, Message message) throws JMSException {
+        if (message instanceof JmsMessage) {
+            return ((JmsMessage) message).copy();
+        } else {
+            JmsMessage activeMessage = null;
+            JmsMessageFactory factory = connection.getMessageFactory();
+
+            if (message instanceof BytesMessage) {
+                BytesMessage bytesMsg = (BytesMessage) message;
+                bytesMsg.reset();
+                JmsBytesMessage msg = factory.createBytesMessage();
+                try {
+                    for (;;) {
+                        // Reads a byte from the message stream until the stream
+                        // is empty
+                        msg.writeByte(bytesMsg.readByte());
+                    }
+                } catch (MessageEOFException e) {
+                    // if an end of message stream as expected
+                } catch (JMSException e) {
+                }
+
+                activeMessage = msg;
+            } else if (message instanceof MapMessage) {
+                MapMessage mapMsg = (MapMessage) message;
+                JmsMapMessage msg = factory.createMapMessage();
+                Enumeration<?> iter = mapMsg.getMapNames();
+
+                while (iter.hasMoreElements()) {
+                    String name = iter.nextElement().toString();
+                    msg.setObject(name, mapMsg.getObject(name));
+                }
+
+                activeMessage = msg;
+            } else if (message instanceof ObjectMessage) {
+                ObjectMessage objMsg = (ObjectMessage) message;
+                JmsObjectMessage msg = factory.createObjectMessage();
+                msg.setObject(objMsg.getObject());
+                activeMessage = msg;
+            } else if (message instanceof StreamMessage) {
+                StreamMessage streamMessage = (StreamMessage) message;
+                streamMessage.reset();
+                JmsStreamMessage msg = factory.createStreamMessage();
+                Object obj = null;
+
+                try {
+                    while ((obj = streamMessage.readObject()) != null) {
+                        msg.writeObject(obj);
+                    }
+                } catch (MessageEOFException e) {
+                    // if an end of message stream as expected
+                } catch (JMSException e) {
+                }
+
+                activeMessage = msg;
+            } else if (message instanceof TextMessage) {
+                TextMessage textMsg = (TextMessage) message;
+                JmsTextMessage msg = factory.createTextMessage();
+                msg.setText(textMsg.getText());
+                activeMessage = msg;
+            } else {
+                activeMessage = factory.createTextMessage();
+            }
+
+            copyProperties(connection, message, activeMessage);
+
+            return activeMessage;
+        }
+    }
+
+    /**
+     * Copies the standard JMS and user defined properties from the givem
+     * message to the specified message
+     *
+     * @param fromMessage
+     *        the message to take the properties from
+     * @param toMessage
+     *        the message to add the properties to
+     * @throws JMSException
+     */
+    public static void copyProperties(JmsConnection connection, Message fromMessage, Message toMessage) throws JMSException {
+        toMessage.setJMSMessageID(fromMessage.getJMSMessageID());
+        toMessage.setJMSCorrelationID(fromMessage.getJMSCorrelationID());
+        toMessage.setJMSReplyTo(transformDestination(connection, fromMessage.getJMSReplyTo()));
+        toMessage.setJMSDestination(transformDestination(connection, fromMessage.getJMSDestination()));
+        toMessage.setJMSDeliveryMode(fromMessage.getJMSDeliveryMode());
+        toMessage.setJMSRedelivered(fromMessage.getJMSRedelivered());
+        toMessage.setJMSType(fromMessage.getJMSType());
+        toMessage.setJMSExpiration(fromMessage.getJMSExpiration());
+        toMessage.setJMSPriority(fromMessage.getJMSPriority());
+        toMessage.setJMSTimestamp(fromMessage.getJMSTimestamp());
+
+        Enumeration<?> propertyNames = fromMessage.getPropertyNames();
+
+        while (propertyNames.hasMoreElements()) {
+            String name = propertyNames.nextElement().toString();
+            Object obj = fromMessage.getObjectProperty(name);
+            toMessage.setObjectProperty(name, obj);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsObjectMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsObjectMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsObjectMessage.java
new file mode 100644
index 0000000..e439764
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsObjectMessage.java
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.message;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+import javax.jms.ObjectMessage;
+
+import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+
+/**
+ * An <CODE>ObjectMessage</CODE> object is used to send a message that contains a serializable
+ * object in the Java programming language ("Java object"). It inherits from the
+ * <CODE>Message</CODE> interface and adds a body containing a single reference to an object.
+ * Only <CODE>Serializable</CODE> Java objects can be used.
+ * <p/>
+ * <p/>
+ * If a collection of Java objects must be sent, one of the <CODE>Collection</CODE> classes
+ * provided since JDK 1.2 can be used.
+ * <p/>
+ * <p/>
+ * When a client receives an <CODE>ObjectMessage</CODE>, it is in read-only mode. If a client
+ * attempts to write to the message at this point, a <CODE>MessageNotWriteableException</CODE>
+ * is thrown. If <CODE>clearBody</CODE> is called, the message can now be both read from and
+ * written to.
+ *
+ * @see javax.jms.Session#createObjectMessage()
+ * @see javax.jms.Session#createObjectMessage(Serializable)
+ * @see javax.jms.BytesMessage
+ * @see javax.jms.MapMessage
+ * @see javax.jms.Message
+ * @see javax.jms.StreamMessage
+ * @see javax.jms.TextMessage
+ */
+public class JmsObjectMessage extends JmsMessage implements ObjectMessage {
+
+    private final JmsObjectMessageFacade facade;
+
+    public JmsObjectMessage(JmsObjectMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsObjectMessage copy() throws JMSException {
+        JmsObjectMessage other = new JmsObjectMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    /**
+     * Sets the serializable object containing this message's data. It is important to note that
+     * an <CODE>ObjectMessage</CODE> contains a snapshot of the object at the time
+     * <CODE>setObject()</CODE> is called; subsequent modifications of the object will have no
+     * effect on the <CODE>ObjectMessage</CODE> body.
+     *
+     * @param newObject
+     *        the message's data
+     * @throws JMSException
+     *         if the JMS provider fails to set the object due to some internal error.
+     * @throws javax.jms.MessageFormatException
+     *         if object serialization fails.
+     * @throws javax.jms.MessageNotWriteableException
+     *         if the message is in read-only mode.
+     */
+    @Override
+    public void setObject(Serializable newObject) throws JMSException {
+        checkReadOnlyBody();
+        try {
+            this.facade.setObject(newObject);
+        } catch (Exception e) {
+            throw new MessageFormatException("Failed to serialize object");
+        }
+    }
+
+    /**
+     * Gets the serializable object containing this message's data. The default value is null.
+     *
+     * @return the serializable object containing this message's data
+     * @throws JMSException
+     */
+    @Override
+    public Serializable getObject() throws JMSException {
+        try {
+            return this.facade.getObject();
+        } catch (Exception e) {
+            throw new MessageFormatException("Failed to read object");
+        }
+    }
+
+    @Override
+    public String toString() {
+        return super.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsOutboundMessageDispatch.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsOutboundMessageDispatch.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsOutboundMessageDispatch.java
new file mode 100644
index 0000000..c77739b
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsOutboundMessageDispatch.java
@@ -0,0 +1,63 @@
+/**
+ * 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.jms.message;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.meta.JmsProducerId;
+
+/**
+ * Envelope that wraps the objects involved in a Message send operation.
+ */
+public class JmsOutboundMessageDispatch {
+
+    private JmsProducerId producerId;
+    private JmsMessage message;
+    private JmsDestination destination;
+    private boolean sendAsync;
+
+    public JmsDestination getDestination() {
+        return destination;
+    }
+
+    public void setDestination(JmsDestination destination) {
+        this.destination = destination;
+    }
+
+    public JmsMessage getMessage() {
+        return message;
+    }
+
+    public void setMessage(JmsMessage message) {
+        this.message = message;
+    }
+
+    public JmsProducerId getProducerId() {
+        return producerId;
+    }
+
+    public void setProducerId(JmsProducerId producerId) {
+        this.producerId = producerId;
+    }
+
+    public void setSendAsync(boolean sendAsync) {
+        this.sendAsync = sendAsync;
+    }
+
+    public boolean isSendAsync() {
+        return sendAsync;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsStreamMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsStreamMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsStreamMessage.java
new file mode 100644
index 0000000..bd4f0fe
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsStreamMessage.java
@@ -0,0 +1,485 @@
+/**
+ * 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.jms.message;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+import javax.jms.StreamMessage;
+
+import org.apache.qpid.jms.message.facade.JmsStreamMessageFacade;
+
+/**
+ * JMS Stream message implementation.
+ */
+public class JmsStreamMessage extends JmsMessage implements StreamMessage {
+
+    private static final int NO_BYTES_IN_FLIGHT = -1;
+
+    private final JmsStreamMessageFacade facade;
+
+    private byte[] bytes;
+    private int remainingBytes = NO_BYTES_IN_FLIGHT;
+
+    public JmsStreamMessage(JmsStreamMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsStreamMessage copy() throws JMSException {
+        JmsStreamMessage other = new JmsStreamMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    @Override
+    public void onSend() throws JMSException {
+        super.onSend();
+        reset();
+    }
+
+    @Override
+    public void clearBody() throws JMSException {
+        super.clearBody();
+        bytes = null;
+        remainingBytes = -1;
+    }
+
+    @Override
+    public boolean readBoolean() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Boolean result = null;
+        Object value;
+        value = facade.peek();
+
+        if (value instanceof Boolean) {
+            result = (Boolean) value;
+        } else if (value instanceof String || value == null) {
+            result = Boolean.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public byte readByte() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Byte result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Byte) {
+            result = (Byte) value;
+        } else if (value instanceof String || value == null) {
+            result = Byte.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public short readShort() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Short result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Short) {
+            result = (Short) value;
+        } else if (value instanceof Byte) {
+            result = ((Byte) value).shortValue();
+        } else if (value instanceof String || value == null) {
+            result = Short.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public char readChar() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Character result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Character) {
+            result = (Character) value;
+        } else if (value == null) {
+                throw new NullPointerException("Cannot convert NULL value to char.");
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public int readInt() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Integer result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Integer) {
+            result = (Integer) value;
+        } else if (value instanceof Short) {
+            result = ((Short) value).intValue();
+        } else if (value instanceof Byte) {
+            result = ((Byte) value).intValue();
+        } else if (value instanceof String || value == null) {
+            result = Integer.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public long readLong() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Long result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Long) {
+            result = (Long) value;
+        } else if (value instanceof Integer) {
+            result = ((Integer) value).longValue();
+        } else if (value instanceof Short) {
+            result = ((Short) value).longValue();
+        } else if (value instanceof Byte) {
+            result = ((Byte) value).longValue();
+        } else if (value instanceof String || value == null) {
+            result = Long.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public float readFloat() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Float result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Float) {
+            result = (Float) value;
+        } else if (value instanceof String || value == null) {
+            result = Float.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public double readDouble() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Double result = null;
+        Object value = facade.peek();
+
+        if (value instanceof Double) {
+            result = (Double) value;
+        } else if (value instanceof Float) {
+            result = ((Float) value).doubleValue();
+        } else if (value instanceof String || value == null) {
+            result = Double.valueOf((String) value);
+        } else {
+            throw new MessageFormatException(
+                "stream value: " + value.getClass().getSimpleName() + " cannot be converted to a boolean.");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public String readString() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        String result = null;
+        Object value = facade.peek();
+
+        if (value == null) {
+            result = null;
+        } else if (value instanceof String) {
+            result = (String) value;
+        } else if (value instanceof Float) {
+            result = value.toString();
+        } else if (value instanceof Double) {
+            result = value.toString();
+        } else if (value instanceof Long) {
+            result = value.toString();
+        } else if (value instanceof Integer) {
+            result = value.toString();
+        } else if (value instanceof Short) {
+            result = value.toString();
+        } else if (value instanceof Byte) {
+            result = value.toString();
+        } else if (value instanceof Boolean) {
+            result = value.toString();
+        } else if (value instanceof Character) {
+            result = value.toString();
+        } else {
+            throw new MessageFormatException("stream cannot convert byte array to String");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public int readBytes(byte[] target) throws JMSException {
+        checkWriteOnlyBody();
+
+        if (target == null) {
+            throw new NullPointerException("target byte array was null");
+        }
+
+        if (remainingBytes == NO_BYTES_IN_FLIGHT) {
+            Object data = facade.peek();
+            if (data == null) {
+                facade.pop();
+                return -1;
+            } else if (!(data instanceof byte[])) {
+                throw new MessageFormatException("Next stream value is not a byte array");
+            }
+
+            bytes = (byte[]) data;
+            remainingBytes = bytes.length;
+        } else if (remainingBytes == 0) {
+            // We previously read all the bytes, but must have filled the destination array.
+            remainingBytes = NO_BYTES_IN_FLIGHT;
+            bytes = null;
+            facade.pop();
+            return -1;
+        }
+
+        int previouslyRead = bytes.length - remainingBytes;
+        int lengthToCopy = Math.min(target.length, remainingBytes);
+
+        if (lengthToCopy > 0) {
+            System.arraycopy(bytes, previouslyRead, target, 0, lengthToCopy);
+        }
+
+        remainingBytes -= lengthToCopy;
+
+        if (remainingBytes == 0 && lengthToCopy < target.length) {
+            // All bytes have been read and the destination array was not filled on this
+            // call, so the return will enable the caller to determine completion immediately.
+            remainingBytes = NO_BYTES_IN_FLIGHT;
+            bytes = null;
+            facade.pop();
+        }
+
+        return lengthToCopy;
+    }
+
+    @Override
+    public Object readObject() throws JMSException {
+        checkWriteOnlyBody();
+        checkBytesInFlight();
+
+        Object result = null;
+        Object value = facade.peek();
+
+        if (value == null) {
+            result = null;
+        } else if (value instanceof String) {
+            result = value;
+        } else if (value instanceof Float) {
+            result = value;
+        } else if (value instanceof Double) {
+            result = value;
+        } else if (value instanceof Long) {
+            result = value;
+        } else if (value instanceof Integer) {
+            result = value;
+        } else if (value instanceof Short) {
+            result = value;
+        } else if (value instanceof Byte) {
+            result = value;
+        } else if (value instanceof Boolean) {
+            result = value;
+        } else if (value instanceof Character) {
+            result = value;
+        } else if (value instanceof byte[]) {
+            byte[] original = (byte[]) value;
+            result = new byte[original.length];
+            System.arraycopy(original, 0, result, 0, original.length);
+        } else {
+            throw new MessageFormatException("Unknown type found in stream");
+        }
+
+        facade.pop();
+        return result;
+    }
+
+    @Override
+    public void writeBoolean(boolean value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeByte(byte value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeShort(short value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeChar(char value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeInt(int value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeLong(long value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeFloat(float value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeDouble(double value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeString(String value) throws JMSException {
+        checkReadOnlyBody();
+        facade.put(value);
+    }
+
+    @Override
+    public void writeBytes(byte[] value) throws JMSException {
+        writeBytes(value, 0, value.length);
+    }
+
+    @Override
+    public void writeBytes(byte[] value, int offset, int length) throws JMSException {
+        checkReadOnlyBody();
+        byte[] copy = new byte[length];
+        System.arraycopy(value, offset, copy, 0, length);
+        facade.put(copy);
+    }
+
+    @Override
+    public void writeObject(Object value) throws JMSException {
+        checkReadOnlyBody();
+        if (value == null) {
+            facade.put(null);
+        } else if (value instanceof String) {
+            facade.put(value);
+        } else if (value instanceof Character) {
+            facade.put(value);
+        } else if (value instanceof Boolean) {
+            facade.put(value);
+        } else if (value instanceof Byte) {
+            facade.put(value);
+        } else if (value instanceof Short) {
+            facade.put(value);
+        } else if (value instanceof Integer) {
+            facade.put(value);
+        } else if (value instanceof Long) {
+            facade.put(value);
+        } else if (value instanceof Float) {
+            facade.put(value);
+        } else if (value instanceof Double) {
+            facade.put(value);
+        } else if (value instanceof byte[]) {
+            writeBytes((byte[]) value);
+        } else {
+            throw new MessageFormatException("Unsupported Object type: " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public void reset() throws JMSException {
+        bytes = null;
+        remainingBytes = NO_BYTES_IN_FLIGHT;
+        setReadOnlyBody(true);
+        facade.reset();
+    }
+
+    @Override
+    public String toString() {
+        // TODO - Better toString()
+        return super.toString() + " JmsStreamMessage{ " + facade + " }";
+    }
+
+    private void checkBytesInFlight() throws MessageFormatException {
+        if (remainingBytes != NO_BYTES_IN_FLIGHT) {
+            throw new MessageFormatException(
+                "Partially read byte[] entry still being retrieved using readBytes(byte[] dest)");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsTextMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsTextMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsTextMessage.java
new file mode 100644
index 0000000..a08550e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsTextMessage.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.jms.message;
+
+import javax.jms.JMSException;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.jms.message.facade.JmsTextMessageFacade;
+
+public class JmsTextMessage extends JmsMessage implements TextMessage {
+
+    private final JmsTextMessageFacade facade;
+
+    public JmsTextMessage(JmsTextMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsTextMessage copy() throws JMSException {
+        JmsTextMessage other = new JmsTextMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    private void copy(JmsTextMessage other) throws JMSException {
+        super.copy(other);
+    }
+
+    @Override
+    public void setText(String text) throws JMSException, MessageNotWriteableException {
+        checkReadOnlyBody();
+        this.facade.setText(text);
+    }
+
+    @Override
+    public String getText() throws JMSException {
+        return facade.getText();
+    }
+
+    @Override
+    public String toString() {
+
+        String text = "";
+        try {
+            text = facade.getText();
+        } catch (JMSException e) {
+        }
+
+        // TODO - Better toString implementation
+        return super.toString() + ":text=" + text;
+    }
+}


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


[14/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/StopWatch.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/StopWatch.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/StopWatch.java
new file mode 100644
index 0000000..72c871d
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/StopWatch.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.jms.util;
+
+/**
+ * A very simple stop watch.
+ * <p/>
+ * This implementation is not thread safe and can only time one task at any given time.
+ */
+public final class StopWatch {
+
+    private long start;
+    private long stop;
+
+    /**
+     * Starts the stop watch
+     */
+    public StopWatch() {
+        this(true);
+    }
+
+    /**
+     * Creates the stop watch
+     *
+     * @param started whether it should start immediately
+     */
+    public StopWatch(boolean started) {
+        if (started) {
+            restart();
+        }
+    }
+
+    /**
+     * Starts or restarts the stop watch
+     */
+    public void restart() {
+        start = System.currentTimeMillis();
+        stop = 0;
+    }
+
+    /**
+     * Stops the stop watch
+     *
+     * @return the time taken in millis.
+     */
+    public long stop() {
+        stop = System.currentTimeMillis();
+        return taken();
+    }
+
+    /**
+     * Returns the time taken in millis.
+     *
+     * @return time in millis
+     */
+    public long taken() {
+        if (start > 0 && stop > 0) {
+            return stop - start;
+        } else if (start > 0) {
+            return System.currentTimeMillis() - start;
+        } else {
+            return 0;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ThreadPoolUtils.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ThreadPoolUtils.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ThreadPoolUtils.java
new file mode 100644
index 0000000..71ae92e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ThreadPoolUtils.java
@@ -0,0 +1,190 @@
+/**
+ * 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.jms.util;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility methods for working with thread pools {@link ExecutorService}.
+ */
+public final class ThreadPoolUtils {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ThreadPoolUtils.class);
+
+    public static final long DEFAULT_SHUTDOWN_AWAIT_TERMINATION = 10 * 1000L;
+
+    /**
+     * Shutdown the given executor service only (ie not graceful shutdown).
+     *
+     * @see java.util.concurrent.ExecutorService#shutdown()
+     */
+    public static void shutdown(ExecutorService executorService) {
+        doShutdown(executorService, 0);
+    }
+
+    /**
+     * Shutdown now the given executor service aggressively.
+     *
+     * @param executorService
+     *        the executor service to shutdown now
+     * @return list of tasks that never commenced execution
+     * @see java.util.concurrent.ExecutorService#shutdownNow()
+     */
+    public static List<Runnable> shutdownNow(ExecutorService executorService) {
+        if (executorService == null) {
+            return Collections.emptyList();
+        }
+
+        List<Runnable> answer = null;
+        if (!executorService.isShutdown()) {
+            LOG.debug("Forcing shutdown of ExecutorService: {}", executorService);
+            answer = executorService.shutdownNow();
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Shutdown of ExecutorService: {} is shutdown: {} and terminated: {}.",
+                    new Object[] { executorService, executorService.isShutdown(), executorService.isTerminated() });
+            }
+        }
+
+        return answer;
+    }
+
+    /**
+     * Shutdown the given executor service graceful at first, and then aggressively if the await
+     * termination timeout was hit.
+     * <p/>
+     * This implementation invokes the
+     * {@link #shutdownGraceful(java.util.concurrent.ExecutorService, long)} with a timeout
+     * value of {@link #DEFAULT_SHUTDOWN_AWAIT_TERMINATION} millis.
+     */
+    public static void shutdownGraceful(ExecutorService executorService) {
+        doShutdown(executorService, DEFAULT_SHUTDOWN_AWAIT_TERMINATION);
+    }
+
+    /**
+     * Shutdown the given executor service graceful at first, and then aggressively if the await
+     * termination timeout was hit.
+     * <p/>
+     * Will try to perform an orderly shutdown by giving the running threads time to complete
+     * tasks, before going more aggressively by doing a
+     * {@link #shutdownNow(java.util.concurrent.ExecutorService)} which forces a shutdown. The
+     * parameter <tt>shutdownAwaitTermination</tt> is used as timeout value waiting for orderly
+     * shutdown to complete normally, before going aggressively.
+     *
+     * @param executorService
+     *        the executor service to shutdown
+     * @param shutdownAwaitTermination
+     *        timeout in millis to wait for orderly shutdown
+     */
+    public static void shutdownGraceful(ExecutorService executorService, long shutdownAwaitTermination) {
+        doShutdown(executorService, shutdownAwaitTermination);
+    }
+
+    private static void doShutdown(ExecutorService executorService, long shutdownAwaitTermination) {
+        if (executorService == null) {
+            return;
+        }
+
+        // shutting down a thread pool is a 2 step process. First we try graceful, and if
+        // that fails, then we go more aggressively and try shutting down again. In both
+        // cases we wait at most the given shutdown timeout value given
+        //
+        // total wait could then be 2 x shutdownAwaitTermination, but when we shutdown the
+        // 2nd time we are aggressive and thus we ought to shutdown much faster
+        if (!executorService.isShutdown()) {
+            boolean warned = false;
+            StopWatch watch = new StopWatch();
+
+            LOG.trace("Shutdown of ExecutorService: {} with await termination: {} millis", executorService, shutdownAwaitTermination);
+            executorService.shutdown();
+
+            if (shutdownAwaitTermination > 0) {
+                try {
+                    if (!awaitTermination(executorService, shutdownAwaitTermination)) {
+                        warned = true;
+                        LOG.warn("Forcing shutdown of ExecutorService: {} due first await termination elapsed.", executorService);
+                        executorService.shutdownNow();
+                        // we are now shutting down aggressively, so wait to see
+                        // if we can completely shutdown or not
+                        if (!awaitTermination(executorService, shutdownAwaitTermination)) {
+                            LOG.warn("Cannot completely force shutdown of ExecutorService: {} due second await termination elapsed.", executorService);
+                        }
+                    }
+                } catch (InterruptedException e) {
+                    warned = true;
+                    LOG.warn("Forcing shutdown of ExecutorService: {} due interrupted.", executorService);
+                    // we were interrupted during shutdown, so force shutdown
+                    executorService.shutdownNow();
+                }
+            }
+
+            // if we logged at WARN level, then report at INFO level when we are
+            // complete so the end user can see this in the log
+            if (warned) {
+                LOG.info("Shutdown of ExecutorService: {} is shutdown: {} and terminated: {} took: {}.",
+                    new Object[] { executorService, executorService.isShutdown(), executorService.isTerminated(), TimeUtils.printDuration(watch.taken()) });
+            } else if (LOG.isDebugEnabled()) {
+                LOG.debug("Shutdown of ExecutorService: {} is shutdown: {} and terminated: {} took: {}.",
+                    new Object[] { executorService, executorService.isShutdown(), executorService.isTerminated(), TimeUtils.printDuration(watch.taken()) });
+            }
+        }
+    }
+
+    /**
+     * Awaits the termination of the thread pool.
+     * <p/>
+     * This implementation will log every 2nd second at INFO level that we are waiting, so the
+     * end user can see we are not hanging in case it takes longer time to terminate the pool.
+     *
+     * @param executorService
+     *        the thread pool
+     * @param shutdownAwaitTermination
+     *        time in millis to use as timeout
+     *
+     * @return <tt>true</tt> if the pool is terminated, or <tt>false</tt> if we timed out
+     *
+     * @throws InterruptedException
+     *         is thrown if we are interrupted during the waiting
+     */
+    public static boolean awaitTermination(ExecutorService executorService, long shutdownAwaitTermination) throws InterruptedException {
+
+        if (executorService == null) {
+            return true;
+        }
+
+        // log progress every 5th second so end user is aware of we are shutting down
+        StopWatch watch = new StopWatch();
+        long interval = Math.min(2000, shutdownAwaitTermination);
+        boolean done = false;
+        while (!done && interval > 0) {
+            if (executorService.awaitTermination(interval, TimeUnit.MILLISECONDS)) {
+                done = true;
+            } else {
+                LOG.info("Waited {} for ExecutorService: {} to terminate...", TimeUtils.printDuration(watch.taken()), executorService);
+                // recalculate interval
+                interval = Math.min(2000, shutdownAwaitTermination - watch.taken());
+            }
+        }
+
+        return done;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TimeUtils.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TimeUtils.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TimeUtils.java
new file mode 100644
index 0000000..979d2f0
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TimeUtils.java
@@ -0,0 +1,73 @@
+/**
+ * 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.jms.util;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Time utils.
+ */
+public final class TimeUtils {
+
+    private TimeUtils() {
+    }
+
+    /**
+     * Prints the duration in a human readable format as X days Y hours Z minutes etc.
+     *
+     * @param uptime
+     *        the uptime in millis
+     * @return the time used for displaying on screen or in logs
+     */
+    public static String printDuration(double uptime) {
+
+        NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
+        NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));
+
+        uptime /= 1000;
+        if (uptime < 60) {
+            return fmtD.format(uptime) + " seconds";
+        }
+        uptime /= 60;
+        if (uptime < 60) {
+            long minutes = (long) uptime;
+            String s = fmtI.format(minutes) + (minutes > 1 ? " minutes" : " minute");
+            return s;
+        }
+        uptime /= 60;
+        if (uptime < 24) {
+            long hours = (long) uptime;
+            long minutes = (long) ((uptime - hours) * 60);
+            String s = fmtI.format(hours) + (hours > 1 ? " hours" : " hour");
+            if (minutes != 0) {
+                s += " " + fmtI.format(minutes) + (minutes > 1 ? " minutes" : " minute");
+            }
+            return s;
+        }
+        uptime /= 24;
+        long days = (long) uptime;
+        long hours = (long) ((uptime - days) * 24);
+        String s = fmtI.format(days) + (days > 1 ? " days" : " day");
+        if (hours != 0) {
+            s += " " + fmtI.format(hours) + (hours > 1 ? " hours" : " hour");
+        }
+        return s;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ToStringSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ToStringSupport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ToStringSupport.java
new file mode 100644
index 0000000..6ed6a3a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/ToStringSupport.java
@@ -0,0 +1,125 @@
+/**
+ * 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.jms.util;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class ToStringSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ToStringSupport.class);
+
+    private ToStringSupport() {
+    }
+
+    public static String toString(Object target) {
+        return toString(target, Object.class, null);
+    }
+
+    @SuppressWarnings({ "rawtypes" })
+    public static String toString(Object target, Class stopClass) {
+        return toString(target, stopClass, null);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public static String toString(Object target, Class stopClass, Map<String, Object> overrideFields) {
+        LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
+        addFields(target, target.getClass(), stopClass, map);
+        if (overrideFields != null) {
+            for(String key : overrideFields.keySet()) {
+                Object value = overrideFields.get(key);
+                map.put(key, value);
+            }
+
+        }
+        StringBuffer buffer = new StringBuffer(simpleName(target.getClass()));
+        buffer.append(" {");
+        Set<Entry<String, Object>> entrySet = map.entrySet();
+        boolean first = true;
+        for (Map.Entry<String,Object> entry : entrySet) {
+            Object value = entry.getValue();
+            Object key = entry.getKey();
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(", ");
+            }
+            buffer.append(key);
+            buffer.append(" = ");
+
+            appendToString(buffer, key, value);
+        }
+        buffer.append("}");
+        return buffer.toString();
+    }
+
+    protected static void appendToString(StringBuffer buffer, Object key, Object value) {
+        if (key.toString().toLowerCase(Locale.ENGLISH).contains("password")){
+            buffer.append("*****");
+        } else {
+            buffer.append(value);
+        }
+    }
+
+    public static String simpleName(Class<?> clazz) {
+        String name = clazz.getName();
+        int p = name.lastIndexOf(".");
+        if (p >= 0) {
+            name = name.substring(p + 1);
+        }
+        return name;
+    }
+
+    @SuppressWarnings({ "rawtypes" })
+    private static void addFields(Object target, Class startClass, Class<Object> stopClass, LinkedHashMap<String, Object> map) {
+
+        if (startClass != stopClass) {
+            addFields(target, startClass.getSuperclass(), stopClass, map);
+        }
+
+        Field[] fields = startClass.getDeclaredFields();
+        for (Field field : fields) {
+            if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())
+                || Modifier.isPrivate(field.getModifiers())) {
+                continue;
+            }
+
+            try {
+                field.setAccessible(true);
+                Object o = field.get(target);
+                if (o != null && o.getClass().isArray()) {
+                    try {
+                        o = Arrays.asList((Object[])o);
+                    } catch (Exception e) {
+                    }
+                }
+                map.put(field.getName(), o);
+            } catch (Exception e) {
+                LOG.debug("Error getting field " + field + " on class " + startClass + ". This exception is ignored.", e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TypeConversionSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TypeConversionSupport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TypeConversionSupport.java
new file mode 100644
index 0000000..08c378c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/TypeConversionSupport.java
@@ -0,0 +1,180 @@
+/**
+ * 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.jms.util;
+
+import java.util.Date;
+import java.util.HashMap;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.JmsQueue;
+
+public final class TypeConversionSupport {
+
+    static class ConversionKey {
+        final Class<?> from;
+        final Class<?> to;
+        final int hashCode;
+
+        public ConversionKey(Class<?> from, Class<?> to) {
+            this.from = from;
+            this.to = to;
+            this.hashCode = from.hashCode() ^ (to.hashCode() << 1);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            ConversionKey x = (ConversionKey) o;
+            return x.from == from && x.to == to;
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCode;
+        }
+    }
+
+    interface Converter {
+        Object convert(Object value);
+    }
+
+    private static final HashMap<ConversionKey, Converter> CONVERSION_MAP = new HashMap<ConversionKey, Converter>();
+
+    static {
+        Converter toStringConverter = new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return value.toString();
+            }
+        };
+        CONVERSION_MAP.put(new ConversionKey(Boolean.class, String.class), toStringConverter);
+        CONVERSION_MAP.put(new ConversionKey(Byte.class, String.class), toStringConverter);
+        CONVERSION_MAP.put(new ConversionKey(Short.class, String.class), toStringConverter);
+        CONVERSION_MAP.put(new ConversionKey(Integer.class, String.class), toStringConverter);
+        CONVERSION_MAP.put(new ConversionKey(Long.class, String.class), toStringConverter);
+        CONVERSION_MAP.put(new ConversionKey(Float.class, String.class), toStringConverter);
+        CONVERSION_MAP.put(new ConversionKey(Double.class, String.class), toStringConverter);
+
+        CONVERSION_MAP.put(new ConversionKey(String.class, Boolean.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Boolean.valueOf((String) value);
+            }
+        });
+        CONVERSION_MAP.put(new ConversionKey(String.class, Byte.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Byte.valueOf((String) value);
+            }
+        });
+        CONVERSION_MAP.put(new ConversionKey(String.class, Short.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Short.valueOf((String) value);
+            }
+        });
+        CONVERSION_MAP.put(new ConversionKey(String.class, Integer.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Integer.valueOf((String) value);
+            }
+        });
+        CONVERSION_MAP.put(new ConversionKey(String.class, Long.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Long.valueOf((String) value);
+            }
+        });
+        CONVERSION_MAP.put(new ConversionKey(String.class, Float.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Float.valueOf((String) value);
+            }
+        });
+        CONVERSION_MAP.put(new ConversionKey(String.class, Double.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Double.valueOf((String) value);
+            }
+        });
+
+        Converter longConverter = new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Long.valueOf(((Number) value).longValue());
+            }
+        };
+        CONVERSION_MAP.put(new ConversionKey(Byte.class, Long.class), longConverter);
+        CONVERSION_MAP.put(new ConversionKey(Short.class, Long.class), longConverter);
+        CONVERSION_MAP.put(new ConversionKey(Integer.class, Long.class), longConverter);
+        CONVERSION_MAP.put(new ConversionKey(Date.class, Long.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Long.valueOf(((Date) value).getTime());
+            }
+        });
+
+        Converter intConverter = new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Integer.valueOf(((Number) value).intValue());
+            }
+        };
+        CONVERSION_MAP.put(new ConversionKey(Byte.class, Integer.class), intConverter);
+        CONVERSION_MAP.put(new ConversionKey(Short.class, Integer.class), intConverter);
+
+        CONVERSION_MAP.put(new ConversionKey(Byte.class, Short.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return Short.valueOf(((Number) value).shortValue());
+            }
+        });
+
+        CONVERSION_MAP.put(new ConversionKey(Float.class, Double.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                return new Double(((Number) value).doubleValue());
+            }
+        });
+
+        CONVERSION_MAP.put(new ConversionKey(String.class, JmsDestination.class), new Converter() {
+            @Override
+            public Object convert(Object value) {
+                // TODO - Right now we go right to a Queue, we need to examine the name
+                //        and correctly map to the appropriate destination type.
+                return new JmsQueue(value.toString());
+            }
+        });
+    }
+
+    private TypeConversionSupport() {
+    }
+
+    public static Object convert(Object value, Class<?> clazz) {
+
+        assert value != null && clazz != null;
+
+        if (value.getClass() == clazz) {
+            return value;
+        }
+
+        Converter c = CONVERSION_MAP.get(new ConversionKey(value.getClass(), clazz));
+        if (c == null) {
+            return null;
+        }
+        return c.convert(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/URISupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/URISupport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/URISupport.java
new file mode 100644
index 0000000..0a649f3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/util/URISupport.java
@@ -0,0 +1,430 @@
+/**
+ * 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.jms.util;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides support methods for dealing with URI values.
+ */
+public class URISupport {
+
+    /**
+     * A composite URI can be split into one or more CompositeData object which each represent
+     * the individual URIs that comprise the composite one.
+     */
+    public static class CompositeData {
+        private String host;
+        private String scheme;
+        private String path;
+        private URI components[];
+        private Map<String, String> parameters;
+        private String fragment;
+
+        public URI[] getComponents() {
+            return components;
+        }
+
+        public String getFragment() {
+            return fragment;
+        }
+
+        public Map<String, String> getParameters() {
+            return parameters;
+        }
+
+        public String getScheme() {
+            return scheme;
+        }
+
+        public String getPath() {
+            return path;
+        }
+
+        public String getHost() {
+            return host;
+        }
+
+        public URI toURI() throws URISyntaxException {
+            StringBuffer sb = new StringBuffer();
+            if (scheme != null) {
+                sb.append(scheme);
+                sb.append(':');
+            }
+
+            if (host != null && host.length() != 0) {
+                sb.append(host);
+            } else {
+                sb.append('(');
+                for (int i = 0; i < components.length; i++) {
+                    if (i != 0) {
+                        sb.append(',');
+                    }
+                    sb.append(components[i].toString());
+                }
+                sb.append(')');
+            }
+
+            if (path != null) {
+                sb.append('/');
+                sb.append(path);
+            }
+            if (!parameters.isEmpty()) {
+                sb.append("?");
+                sb.append(PropertyUtil.createQueryString(parameters));
+            }
+            if (fragment != null) {
+                sb.append("#");
+                sb.append(fragment);
+            }
+            return new URI(sb.toString());
+        }
+    }
+
+    /**
+     * Given a composite URI, parse the individual URI elements contained within that URI and
+     * return a CompsoteData instance that contains the parsed URI values.
+     *
+     * @param uri
+     *        The target URI that should be parsed.
+     *
+     * @return a new CompsiteData instance representing the parsed composite URI.
+     * @throws URISyntaxException
+     */
+    public static CompositeData parseComposite(URI uri) throws URISyntaxException {
+
+        CompositeData rc = new CompositeData();
+        rc.scheme = uri.getScheme();
+        String ssp = PropertyUtil.stripPrefix(uri.getRawSchemeSpecificPart().trim(), "//").trim();
+
+        try {
+            parseComposite(uri, rc, ssp);
+        } catch (Exception e) {
+            throw new URISyntaxException(uri.toString(), e.getMessage());
+        }
+
+        rc.fragment = uri.getFragment();
+        return rc;
+    }
+
+    /**
+     * Given a composite URI and a CompositeData instance and the scheme specific part extracted
+     * from the source URI, parse the composite URI and populate the CompositeData object with
+     * the results. The source URI is used only for logging as the ssp should have already been
+     * extracted from it and passed here.
+     *
+     * @param uri
+     *        The original source URI whose ssp is parsed into the composite data.
+     * @param rc
+     *        The CompsositeData instance that will be populated from the given ssp.
+     * @param ssp
+     *        The scheme specific part from the original string that is a composite or one or
+     *        more URIs.
+     *
+     * @throws URISyntaxException
+     */
+    private static void parseComposite(URI uri, CompositeData rc, String ssp) throws Exception {
+        String componentString;
+        String params;
+
+        if (!checkParenthesis(ssp)) {
+            throw new URISyntaxException(uri.toString(), "Not a matching number of '(' and ')' parenthesis");
+        }
+
+        int p;
+        int initialParen = ssp.indexOf("(");
+        if (initialParen == 0) {
+
+            rc.host = ssp.substring(0, initialParen);
+            p = rc.host.indexOf("/");
+
+            if (p >= 0) {
+                rc.path = rc.host.substring(p);
+                rc.host = rc.host.substring(0, p);
+            }
+
+            p = indexOfParenthesisMatch(ssp, initialParen);
+            componentString = ssp.substring(initialParen + 1, p);
+            params = ssp.substring(p + 1).trim();
+
+        } else {
+            componentString = ssp;
+            params = "";
+        }
+
+        String components[] = splitComponents(componentString);
+        rc.components = new URI[components.length];
+        for (int i = 0; i < components.length; i++) {
+            rc.components[i] = new URI(components[i].trim());
+        }
+
+        p = params.indexOf("?");
+        if (p >= 0) {
+            if (p > 0) {
+                rc.path = PropertyUtil.stripPrefix(params.substring(0, p), "/");
+            }
+            rc.parameters = PropertyUtil.parseQuery(params.substring(p + 1));
+        } else {
+            if (params.length() > 0) {
+                rc.path = PropertyUtil.stripPrefix(params, "/");
+            }
+            rc.parameters = Collections.emptyMap();
+        }
+    }
+
+    /**
+     * Examine a URI and determine if it is a Composite type or not.
+     *
+     * @param uri
+     *        The URI that is to be examined.
+     *
+     * @return true if the given URI is a Composite type.
+     */
+    public static boolean isCompositeURI(URI uri) {
+        String ssp = PropertyUtil.stripPrefix(uri.getRawSchemeSpecificPart().trim(), "//").trim();
+
+        if (ssp.indexOf('(') == 0 && checkParenthesis(ssp)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Examine the supplied string and ensure that all parends appear as matching pairs.
+     *
+     * @param str
+     *        The target string to examine.
+     *
+     * @return true if the target string has valid parend pairings.
+     */
+    public static boolean checkParenthesis(String str) {
+        boolean result = true;
+        if (str != null) {
+            int open = 0;
+            int closed = 0;
+
+            int i = 0;
+            while ((i = str.indexOf('(', i)) >= 0) {
+                i++;
+                open++;
+            }
+            i = 0;
+            while ((i = str.indexOf(')', i)) >= 0) {
+                i++;
+                closed++;
+            }
+            result = open == closed;
+        }
+        return result;
+    }
+
+    /**
+     * Given a string and a position in that string of an open parend, find the matching close
+     * parend.
+     *
+     * @param str
+     *        The string to be searched for a matching parend.
+     * @param first
+     *        The index in the string of the opening parend whose close value is to be searched.
+     *
+     * @return the index in the string where the closing parend is located.
+     *
+     * @throws URISyntaxException
+     *         if the string does not contain a matching parend.
+     */
+    public static int indexOfParenthesisMatch(String str, int first) throws URISyntaxException {
+        int index = -1;
+
+        if (first < 0 || first > str.length()) {
+            throw new IllegalArgumentException("Invalid position for first parenthesis: " + first);
+        }
+
+        if (str.charAt(first) != '(') {
+            throw new IllegalArgumentException("character at indicated position is not a parenthesis");
+        }
+
+        int depth = 1;
+        char[] array = str.toCharArray();
+        for (index = first + 1; index < array.length; ++index) {
+            char current = array[index];
+            if (current == '(') {
+                depth++;
+            } else if (current == ')') {
+                if (--depth == 0) {
+                    break;
+                }
+            }
+        }
+
+        if (depth != 0) {
+            throw new URISyntaxException(str, "URI did not contain a matching parenthesis.");
+        }
+
+        return index;
+    }
+
+    /**
+     * Given the inner portion of a composite URI, split and return each inner URI as a string
+     * element in a new String array.
+     *
+     * @param str
+     *        The inner URI elements of a composite URI string.
+     *
+     * @return an array containing each inner URI from the composite one.
+     */
+    public static String[] splitComponents(String str) {
+        List<String> l = new ArrayList<String>();
+
+        int last = 0;
+        int depth = 0;
+        char chars[] = str.toCharArray();
+        for (int i = 0; i < chars.length; i++) {
+            switch (chars[i]) {
+                case '(':
+                    depth++;
+                    break;
+                case ')':
+                    depth--;
+                    break;
+                case ',':
+                    if (depth == 0) {
+                        String s = str.substring(last, i);
+                        l.add(s);
+                        last = i + 1;
+                    }
+                    break;
+                default:
+            }
+        }
+
+        String s = str.substring(last);
+        if (s.length() != 0) {
+            l.add(s);
+        }
+
+        String rc[] = new String[l.size()];
+        l.toArray(rc);
+        return rc;
+    }
+
+    /**
+     * Removes any URI query from the given uri and return a new URI that does not contain the
+     * query portion.
+     *
+     * @param uri
+     *        The URI whose query value is to be removed.
+     *
+     * @return a new URI that does not contain a query value.
+     * @throws URISyntaxException
+     */
+    public static URI removeQuery(URI uri) throws URISyntaxException {
+        return PropertyUtil.replaceQuery(uri, (String) null);
+    }
+
+    /**
+     * Given a URI parse and extract any URI query options and return them as a Key / Value
+     * mapping.
+     *
+     * This method differs from the {@link parseQuery} method in that it handles composite URI
+     * types and will extract the URI options from the outermost composite URI.
+     *
+     * @param uri
+     *        The URI whose query should be extracted and processed.
+     *
+     * @return A Mapping of the URI options.
+     * @throws URISyntaxException
+     */
+    public static Map<String, String> parseParameters(URI uri) throws URISyntaxException {
+        if (!isCompositeURI(uri)) {
+            if (uri.getQuery() == null) {
+                return Collections.emptyMap();
+            } else {
+                try {
+                    return PropertyUtil.parseQuery(PropertyUtil.stripPrefix(uri.getQuery(), "?"));
+                } catch (Exception e) {
+                    throw new URISyntaxException(uri.toString(), e.getMessage());
+                }
+            }
+        } else {
+            CompositeData data = URISupport.parseComposite(uri);
+            Map<String, String> parameters = new HashMap<String, String>();
+            parameters.putAll(data.getParameters());
+            if (parameters.isEmpty()) {
+                parameters = Collections.emptyMap();
+            }
+
+            return parameters;
+        }
+    }
+
+    /**
+     * Given a Key / Value mapping create and append a URI query value that represents the
+     * mapped entries, return the newly updated URI that contains the value of the given URI and
+     * the appended query value.
+     *
+     * @param uri
+     *        The source URI that will have the Map entries appended as a URI query value.
+     * @param queryParameters
+     *        The Key / Value mapping that will be transformed into a URI query string.
+     *
+     * @return A new URI value that combines the given URI and the constructed query string.
+     * @throws URISyntaxException
+     */
+    public static URI applyParameters(URI uri, Map<String, String> queryParameters) throws URISyntaxException {
+        return applyParameters(uri, queryParameters, "");
+    }
+
+    /**
+     * Given a Key / Value mapping create and append a URI query value that represents the
+     * mapped entries, return the newly updated URI that contains the value of the given URI and
+     * the appended query value. Each entry in the query string is prefixed by the supplied
+     * optionPrefix string.
+     *
+     * @param uri
+     *        The source URI that will have the Map entries appended as a URI query value.
+     * @param queryParameters
+     *        The Key / Value mapping that will be transformed into a URI query string.
+     * @param optionPrefix
+     *        A string value that when not null or empty is used to prefix each query option
+     *        key.
+     *
+     * @return A new URI value that combines the given URI and the constructed query string.
+     * @throws URISyntaxException
+     */
+    public static URI applyParameters(URI uri, Map<String, String> queryParameters, String optionPrefix) throws URISyntaxException {
+        if (queryParameters != null && !queryParameters.isEmpty()) {
+            StringBuffer newQuery = uri.getRawQuery() != null ? new StringBuffer(uri.getRawQuery()) : new StringBuffer();
+            for (Map.Entry<String, String> param : queryParameters.entrySet()) {
+                if (param.getKey().startsWith(optionPrefix)) {
+                    if (newQuery.length() != 0) {
+                        newQuery.append('&');
+                    }
+                    final String key = param.getKey().substring(optionPrefix.length());
+                    newQuery.append(key).append('=').append(param.getValue());
+                }
+            }
+            uri = PropertyUtil.replaceQuery(uri, newQuery.toString());
+        }
+        return uri;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp
new file mode 100644
index 0000000..fe3ecca
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.amqp.AmqpProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio
new file mode 100644
index 0000000..fe3ecca
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.amqp.AmqpProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio+ssl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio+ssl b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio+ssl
new file mode 100644
index 0000000..69cd431
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+nio+ssl
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.amqp.AmqpSslProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+ssl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+ssl b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+ssl
new file mode 100644
index 0000000..69cd431
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqp+ssl
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.amqp.AmqpSslProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqps
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqps b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqps
new file mode 100644
index 0000000..69cd431
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/amqps
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.amqp.AmqpSslProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/failover
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/failover b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/failover
new file mode 100644
index 0000000..b66f21e
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/provider/failover
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.provider.failover.FailoverProviderFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/ANONYMOUS
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/ANONYMOUS b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/ANONYMOUS
new file mode 100644
index 0000000..00b9f52
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/ANONYMOUS
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.sasl.AnonymousMechanismFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/CRAM-MD5
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/CRAM-MD5 b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/CRAM-MD5
new file mode 100644
index 0000000..fb2d223
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/CRAM-MD5
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.sasl.CramMD5MechanismFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/PLAIN
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/PLAIN b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/PLAIN
new file mode 100644
index 0000000..cf06fa1
--- /dev/null
+++ b/qpid-jms-client/src/main/resources/META-INF/services/org/apache/qpid/jms/sasl/PLAIN
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+class=org.apache.qpid.jms.sasl.PlainMechanismFactory

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.java
new file mode 100644
index 0000000..3a7b6ac
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/ConnectionIntegrationTest.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.jms.integration;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionMetaData;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.test.QpidJmsTestCase;
+import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
+import org.junit.Test;
+
+// TODO find a way to make the test abort immediately if the TestAmqpPeer throws an exception
+public class ConnectionIntegrationTest extends QpidJmsTestCase {
+    private final IntegrationTestFixture testFixture = new IntegrationTestFixture();
+
+    @Test(timeout=10000)
+    public void testCreateAndCloseConnection() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectClose();
+            connection.close();
+        }
+    }
+
+    @Test(timeout=10000)
+    public void testCreateAutoAckSession() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+            testPeer.expectBegin(true);
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+            assertNotNull("Session should not be null", session);
+        }
+    }
+
+    @Test(timeout=5000)
+    public void testConnectionMetaDataVersion() throws Exception {
+        try (TestAmqpPeer testPeer = new TestAmqpPeer(IntegrationTestFixture.PORT);) {
+            Connection connection = testFixture.establishConnecton(testPeer);
+
+            ConnectionMetaData meta = connection.getMetaData();
+            assertTrue("Expected non-zero provider major version", meta.getProviderMajorVersion() != 0);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/IntegrationTestFixture.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/IntegrationTestFixture.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/IntegrationTestFixture.java
new file mode 100644
index 0000000..cf19d67
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/integration/IntegrationTestFixture.java
@@ -0,0 +1,48 @@
+/*
+ * 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.jms.integration;
+
+import static org.junit.Assert.assertNull;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.test.testpeer.TestAmqpPeer;
+
+public class IntegrationTestFixture {
+    static final int PORT = 25672;
+
+    Connection establishConnecton(TestAmqpPeer testPeer) throws JMSException {
+        testPeer.expectPlainConnect("guest", "guest", true);
+
+        // Each connection creates a session for managing temporary destinations etc
+        testPeer.expectBegin(true);
+
+        ConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:" + PORT);
+        Connection connection = factory.createConnection("guest", "guest");
+
+        // Set a clientId to provoke the actual AMQP connection process to occur.
+        connection.setClientID("clientName");
+
+        assertNull(testPeer.getThrowable());
+        return connection;
+    }
+}


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


[12/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsBytesMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsBytesMessageTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsBytesMessageTest.java
new file mode 100644
index 0000000..5f29da1
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsBytesMessageTest.java
@@ -0,0 +1,666 @@
+/**
+ * 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.jms.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Arrays;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.message.JmsBytesMessage;
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultBytesMessageFacade;
+import org.fusesource.hawtbuf.Buffer;
+import org.junit.Test;
+
+/**
+ * Test for JMS Spec compliance for the JmsBytesMessage class using the default message facade.
+ */
+public class JmsBytesMessageTest {
+
+    private static final int END_OF_STREAM = -1;
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    /**
+     * Test that calling {@link BytesMessage#getBodyLength()} on a new message which has been
+     * populated and {@link BytesMessage#reset()} causes the length to be reported correctly.
+     */
+    @Test
+    public void testResetOnNewlyPopulatedBytesMessageUpdatesBodyLength() throws Exception {
+        byte[] bytes = "newResetTestBytes".getBytes();
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.writeBytes(bytes);
+        bytesMessage.reset();
+        assertEquals("Message reports unexpected length", bytes.length, bytesMessage.getBodyLength());
+    }
+
+    /**
+     * Test that attempting to call {@link BytesMessage#getBodyLength()} on a new message causes
+     * a {@link MessageNotReadableException} to be thrown due to being write-only.
+     */
+    @Test(expected = MessageNotReadableException.class)
+    public void testGetBodyLengthOnNewMessageThrowsMessageNotReadableException() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.getBodyLength();
+    }
+
+    @Test
+    public void testReadBytesUsingReceivedMessageWithNoBodyReturnsEOS() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.onSend();
+        //verify attempting to read bytes returns -1, i.e EOS
+        assertEquals("Expected input stream to be at end but data was returned", END_OF_STREAM, bytesMessage.readBytes(new byte[1]));
+    }
+
+    @Test
+    public void testReadBytesUsingReceivedMessageWithBodyReturnsBytes() throws Exception {
+        Buffer content = new Buffer("myBytesData".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+        bytesMessage.onSend();
+
+        // retrieve the expected bytes, check they match
+        byte[] receivedBytes = new byte[content.length];
+        bytesMessage.readBytes(receivedBytes);
+        assertTrue(Arrays.equals(content.data, receivedBytes));
+
+        // verify no more bytes remain, i.e EOS
+        assertEquals("Expected input stream to be at end but data was returned",
+                     END_OF_STREAM, bytesMessage.readBytes(new byte[1]));
+
+        assertEquals("Message reports unexpected length", content.length, bytesMessage.getBodyLength());
+    }
+
+    /**
+     * Test that attempting to write bytes to a received message (without calling {@link BytesMessage#clearBody()} first)
+     * causes a {@link MessageNotWriteableException} to be thrown due to being read-only.
+     */
+    @Test(expected = MessageNotWriteableException.class)
+    public void testReceivedBytesMessageThrowsMessageNotWriteableExceptionOnWriteBytes() throws Exception {
+        Buffer content = new Buffer("myBytesData".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+        bytesMessage.onSend();
+        bytesMessage.writeBytes(content.data);
+    }
+
+    /**
+     * Test that attempting to read bytes from a new message (without calling {@link BytesMessage#reset()} first) causes a
+     * {@link MessageNotReadableException} to be thrown due to being write-only.
+     */
+    @Test(expected = MessageNotReadableException.class)
+    public void testNewBytesMessageThrowsMessageNotReadableOnReadBytes() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        byte[] receivedBytes = new byte[1];
+        bytesMessage.readBytes(receivedBytes);
+    }
+
+    /**
+     * Test that calling {@link BytesMessage#clearBody()} causes a received
+     * message to become writable
+     */
+    @Test
+    public void testClearBodyOnReceivedBytesMessageMakesMessageWritable() throws Exception {
+        Buffer content = new Buffer("myBytesData".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+        bytesMessage.onSend();
+        assertTrue("Message should not be writable", bytesMessage.isReadOnlyBody());
+        bytesMessage.clearBody();
+        assertFalse("Message should be writable", bytesMessage.isReadOnlyBody());
+    }
+
+    /**
+     * Test that calling {@link BytesMessage#clearBody()} of a received message
+     * causes the body of the underlying {@link AmqpBytesMessage} to be emptied.
+     */
+    @Test
+    public void testClearBodyOnReceivedBytesMessageClearsUnderlyingMessageBody() throws Exception {
+        Buffer content = new Buffer("myBytesData".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+        bytesMessage.onSend();
+
+        assertNotNull("Expected message content but none was present", facade.getContent());
+        bytesMessage.clearBody();
+        assertNull("Expected no message content but was present", facade.getContent());
+    }
+
+    /**
+     * Test that attempting to call {@link BytesMessage#getBodyLength()} on a received message after calling
+     * {@link BytesMessage#clearBody()} causes {@link MessageNotReadableException} to be thrown due to being write-only.
+     */
+    @Test
+    public void testGetBodyLengthOnClearedReceivedMessageThrowsMessageNotReadableException() throws Exception {
+        Buffer content = new Buffer("myBytesData".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+        bytesMessage.onSend();
+        assertEquals("Unexpected message length", content.length, bytesMessage.getBodyLength());
+        bytesMessage.clearBody();
+
+        try {
+            bytesMessage.getBodyLength();
+            fail("expected exception to be thrown");
+        } catch (MessageNotReadableException mnre) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link BytesMessage#reset()} causes a write-only
+     * message to become read-only
+     */
+    @Test
+    public void testResetOnReceivedBytesMessageResetsMarker() throws Exception {
+        Buffer content = new Buffer("resetTestBytes".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+        bytesMessage.onSend();
+
+        // retrieve a few bytes, check they match the first few expected bytes
+        byte[] partialBytes = new byte[3];
+        bytesMessage.readBytes(partialBytes);
+        byte[] partialOriginalBytes = Arrays.copyOf(content.data, 3);
+        assertTrue(Arrays.equals(partialOriginalBytes, partialBytes));
+
+        bytesMessage.reset();
+
+        // retrieve all the expected bytes, check they match
+        byte[] resetBytes = new byte[content.length];
+        bytesMessage.readBytes(resetBytes);
+        assertTrue(Arrays.equals(content.data, resetBytes));
+    }
+
+    /**
+     * Test that calling {@link BytesMessage#reset()} on a new message which has been populated
+     * causes the marker to be reset and makes the message read-only
+     */
+    @Test
+    public void testResetOnNewlyPopulatedBytesMessageResetsMarkerAndMakesReadable() throws Exception {
+        Buffer content = new Buffer("newResetTestBytes".getBytes());
+        JmsDefaultBytesMessageFacade facade = new JmsDefaultBytesMessageFacade();
+        facade.setContent(content);
+
+        JmsBytesMessage bytesMessage = new JmsBytesMessage(facade);
+
+        assertFalse("Message should be writable", bytesMessage.isReadOnlyBody());
+        bytesMessage.writeBytes(content.data);
+        bytesMessage.reset();
+        assertTrue("Message should not be writable", bytesMessage.isReadOnlyBody());
+
+        // retrieve the bytes, check they match
+        byte[] resetBytes = new byte[content.length];
+        bytesMessage.readBytes(resetBytes);
+        assertTrue(Arrays.equals(content.data, resetBytes));
+    }
+
+    /**
+     * Verify that nothing is read when {@link BytesMessage#readBytes(byte[])} is
+     * called with a zero length destination array.
+     */
+    @Test
+    public void testReadBytesWithZeroLengthDestination() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.reset();
+        assertEquals("Did not expect any bytes to be read", 0, bytesMessage.readBytes(new byte[0]));
+    }
+
+    /**
+     * Verify that when {@link BytesMessage#readBytes(byte[], int))} is called
+     * with a negative length that an {@link IndexOutOfBoundsException} is thrown.
+     */
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testReadBytesWithNegativeLengthThrowsIOOBE() throws Exception
+    {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.reset();
+        bytesMessage.readBytes(new byte[0], -1);
+    }
+
+    /**
+     * Verify that when {@link BytesMessage#readBytes(byte[], int))} is called
+     * with a length that is greater than the size of the provided array,
+     * an {@link IndexOutOfBoundsException} is thrown.
+     */
+    @Test(expected=IndexOutOfBoundsException.class)
+    public void testReadBytesWithLengthGreatThanArraySizeThrowsIOOBE() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.reset();
+        bytesMessage.readBytes(new byte[1], 2);
+    }
+
+    /**
+     * Test that writing a null using {@link BytesMessage#writeObject(Object)}
+     * results in a NPE being thrown.
+     */
+    @Test(expected=NullPointerException.class)
+    public void testWriteObjectWithNullThrowsNPE() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.writeObject(null);
+    }
+
+    /**
+     * Test that writing a null using {@link BytesMessage#writeObject(Object)}
+     * results in an {@link MessageFormatException} being thrown.
+     */
+    @Test(expected=MessageFormatException.class)
+    public void testWriteObjectWithIllegalTypeThrowsMFE() throws Exception {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        bytesMessage.writeObject(new Object());
+    }
+
+    @Test
+    public void testGetBodyLength() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        int len = 10;
+        for (int i = 0; i < len; i++) {
+            msg.writeLong(5L);
+        }
+
+        msg.reset();
+        assertTrue(msg.getBodyLength() == (len * 8));
+    }
+
+    @Test
+    public void testReadBoolean() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeBoolean(true);
+        msg.reset();
+        assertTrue(msg.readBoolean());
+    }
+
+    @Test
+    public void testReadByte() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeByte((byte) 2);
+        msg.reset();
+        assertTrue(msg.readByte() == 2);
+    }
+
+    @Test
+    public void testReadUnsignedByte() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeByte((byte) 2);
+        msg.reset();
+        assertTrue(msg.readUnsignedByte() == 2);
+    }
+
+    @Test
+    public void testReadShort() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeShort((short) 3000);
+        msg.reset();
+        assertTrue(msg.readShort() == 3000);
+    }
+
+    @Test
+    public void testReadUnsignedShort() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeShort((short) 3000);
+        msg.reset();
+        assertTrue(msg.readUnsignedShort() == 3000);
+    }
+
+    @Test
+    public void testReadChar() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeChar('a');
+        msg.reset();
+        assertTrue(msg.readChar() == 'a');
+    }
+
+    @Test
+    public void testReadInt() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeInt(3000);
+        msg.reset();
+        assertTrue(msg.readInt() == 3000);
+    }
+
+    @Test
+    public void testReadLong() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeLong(3000);
+        msg.reset();
+        assertTrue(msg.readLong() == 3000);
+    }
+
+    @Test
+    public void testReadFloat() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeFloat(3.3f);
+        msg.reset();
+        assertTrue(msg.readFloat() == 3.3f);
+    }
+
+    @Test
+    public void testReadDouble() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        msg.writeDouble(3.3d);
+        msg.reset();
+        assertTrue(msg.readDouble() == 3.3d);
+    }
+
+    @Test
+    public void testReadUTF() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        String str = "this is a test";
+        msg.writeUTF(str);
+        msg.reset();
+        assertTrue(msg.readUTF().equals(str));
+    }
+
+    @Test
+    public void testReadBytesbyteArray() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        byte[] data = new byte[50];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = (byte) i;
+        }
+        msg.writeBytes(data);
+        msg.reset();
+        byte[] test = new byte[data.length];
+        msg.readBytes(test);
+        for (int i = 0; i < test.length; i++) {
+            assertTrue(test[i] == i);
+        }
+    }
+
+    @Test
+    public void testWriteObject() throws JMSException {
+        JmsBytesMessage msg = factory.createBytesMessage();
+        try {
+            msg.writeObject("fred");
+            msg.writeObject(Boolean.TRUE);
+            msg.writeObject(Character.valueOf('q'));
+            msg.writeObject(Byte.valueOf((byte) 1));
+            msg.writeObject(Short.valueOf((short) 3));
+            msg.writeObject(Integer.valueOf(3));
+            msg.writeObject(Long.valueOf(300L));
+            msg.writeObject(new Float(3.3f));
+            msg.writeObject(new Double(3.3));
+            msg.writeObject(new byte[3]);
+        } catch (MessageFormatException mfe) {
+            fail("objectified primitives should be allowed");
+        }
+        try {
+            msg.writeObject(new Object());
+            fail("only objectified primitives are allowed");
+        } catch (MessageFormatException mfe) {
+        }
+    }
+
+    @Test
+    public void testClearBody() throws JMSException {
+        JmsBytesMessage bytesMessage = factory.createBytesMessage();
+        try {
+            bytesMessage.writeInt(1);
+            bytesMessage.clearBody();
+            assertFalse(bytesMessage.isReadOnlyBody());
+            bytesMessage.writeInt(1);
+            bytesMessage.readInt();
+        } catch (MessageNotReadableException mnwe) {
+        } catch (MessageNotWriteableException mnwe) {
+            assertTrue(false);
+        }
+    }
+
+    @Test
+    public void testReset() throws JMSException {
+        JmsBytesMessage message = factory.createBytesMessage();
+        try {
+            message.writeDouble(24.5);
+            message.writeLong(311);
+        } catch (MessageNotWriteableException mnwe) {
+            fail("should be writeable");
+        }
+        message.reset();
+        try {
+            assertTrue(message.isReadOnlyBody());
+            assertEquals(message.readDouble(), 24.5, 0);
+            assertEquals(message.readLong(), 311);
+        } catch (MessageNotReadableException mnre) {
+            fail("should be readable");
+        }
+        try {
+            message.writeInt(33);
+            fail("should throw exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+    }
+
+    @Test
+    public void testReadOnlyBody() throws JMSException {
+        JmsBytesMessage message = factory.createBytesMessage();
+        try {
+            message.writeBoolean(true);
+            message.writeByte((byte) 1);
+            message.writeByte((byte) 1);
+            message.writeBytes(new byte[1]);
+            message.writeBytes(new byte[3], 0, 2);
+            message.writeChar('a');
+            message.writeDouble(1.5);
+            message.writeFloat((float) 1.5);
+            message.writeInt(1);
+            message.writeLong(1);
+            message.writeObject("stringobj");
+            message.writeShort((short) 1);
+            message.writeShort((short) 1);
+            message.writeUTF("utfstring");
+        } catch (MessageNotWriteableException mnwe) {
+            fail("Should be writeable");
+        }
+        message.reset();
+        try {
+            message.readBoolean();
+            message.readByte();
+            message.readUnsignedByte();
+            message.readBytes(new byte[1]);
+            message.readBytes(new byte[2], 2);
+            message.readChar();
+            message.readDouble();
+            message.readFloat();
+            message.readInt();
+            message.readLong();
+            message.readUTF();
+            message.readShort();
+            message.readUnsignedShort();
+            message.readUTF();
+        } catch (MessageNotReadableException mnwe) {
+            fail("Should be readable");
+        }
+        try {
+            message.writeBoolean(true);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeByte((byte) 1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeBytes(new byte[1]);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeBytes(new byte[3], 0, 2);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeChar('a');
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeDouble(1.5);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeFloat((float) 1.5);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeInt(1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeLong(1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeObject("stringobj");
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeShort((short) 1);
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+        try {
+            message.writeUTF("utfstring");
+            fail("Should have thrown exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+    }
+
+    @Test
+    public void testWriteOnlyBody() throws JMSException {
+        JmsBytesMessage message = factory.createBytesMessage();
+        message.clearBody();
+        try {
+            message.writeBoolean(true);
+            message.writeByte((byte) 1);
+            message.writeByte((byte) 1);
+            message.writeBytes(new byte[1]);
+            message.writeBytes(new byte[3], 0, 2);
+            message.writeChar('a');
+            message.writeDouble(1.5);
+            message.writeFloat((float) 1.5);
+            message.writeInt(1);
+            message.writeLong(1);
+            message.writeObject("stringobj");
+            message.writeShort((short) 1);
+            message.writeShort((short) 1);
+            message.writeUTF("utfstring");
+        } catch (MessageNotWriteableException mnwe) {
+            fail("Should be writeable");
+        }
+        try {
+            message.readBoolean();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException mnwe) {
+        }
+        try {
+            message.readByte();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readUnsignedByte();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readBytes(new byte[1]);
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readBytes(new byte[2], 2);
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readChar();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readDouble();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readFloat();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readInt();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readLong();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readUTF();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readShort();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readUnsignedShort();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+        try {
+            message.readUTF();
+            fail("Should have thrown exception");
+        } catch (MessageNotReadableException e) {
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMapMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMapMessageTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMapMessageTest.java
new file mode 100644
index 0000000..9b335af
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsMapMessageTest.java
@@ -0,0 +1,911 @@
+/**
+ * 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.jms.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMapMessage;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.facade.JmsMapMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMapMessageFacade;
+import org.junit.Test;
+
+/**
+ * Test that the JMS level JmsMapMessage using a simple default message facade follows
+ * the JMS spec.
+ */
+public class JmsMapMessageTest {
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    // ======= general =========
+
+    @Test
+    public void testGetMapNamesWithNewMessageToSendReturnsEmptyEnumeration() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+        Enumeration<?> names = mapMessage.getMapNames();
+
+        assertFalse("Expected new message to have no map names", names.hasMoreElements());
+    }
+
+    /**
+     * Test that we are able to retrieve the names and values of map entries on a received
+     * message
+     */
+    @Test
+    public void testGetMapNamesUsingReceivedMessageReturnsExpectedEnumeration() throws Exception {
+        JmsMapMessageFacade facade = new JmsDefaultMapMessageFacade();
+        String myKey1 = "key1";
+        String myKey2 = "key2";
+        facade.put(myKey1, "value1");
+        facade.put(myKey2, "value2");
+
+        JmsMapMessage mapMessage = new JmsMapMessage(facade);
+        Enumeration<?> names = mapMessage.getMapNames();
+
+        int count = 0;
+        List<Object> elements = new ArrayList<Object>();
+        while (names.hasMoreElements()) {
+            count++;
+            elements.add(names.nextElement());
+        }
+        assertEquals("expected 2 map keys in enumeration", 2, count);
+        assertTrue("expected key was not found: " + myKey1, elements.contains(myKey1));
+        assertTrue("expected key was not found: " + myKey2, elements.contains(myKey2));
+    }
+
+    /**
+     * Test that we enforce the requirement that map message key names not be null or the empty
+     * string.
+     */
+    @Test
+    public void testSetObjectWithNullOrEmptyKeyNameThrowsIAE() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+        try {
+            mapMessage.setObject(null, "value");
+            fail("Expected exception not thrown");
+        } catch (IllegalArgumentException iae) {
+            // expected
+        }
+
+        try {
+            mapMessage.setObject("", "value");
+            fail("Expected exception not thrown");
+        } catch (IllegalArgumentException iae) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that we are not able to write to a received message without calling
+     * {@link JmsMapMessage#clearBody()}
+     */
+    @Test
+    public void testReceivedMessageIsReadOnlyAndThrowsMNWE() throws Exception {
+        JmsMapMessageFacade facade = new JmsDefaultMapMessageFacade();
+        String myKey1 = "key1";
+        facade.put(myKey1, "value1");
+        JmsMapMessage mapMessage = new JmsMapMessage(facade);
+        mapMessage.onSend();
+
+        try {
+            mapMessage.setObject("name", "value");
+            fail("expected exception to be thrown");
+        } catch (MessageNotWriteableException mnwe) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that calling {@link JmsMapMessage#clearBody()} makes a received message writable
+     */
+    @Test
+    public void testClearBodyMakesReceivedMessageWritable() throws Exception {
+        JmsMapMessageFacade facade = new JmsDefaultMapMessageFacade();
+        String myKey1 = "key1";
+        facade.put(myKey1, "value1");
+
+        JmsMapMessage mapMessage = new JmsMapMessage(facade);
+        mapMessage.onSend();
+
+        assertTrue("expected message to be read-only", mapMessage.isReadOnlyBody());
+        mapMessage.clearBody();
+        assertFalse("expected message to be writable", mapMessage.isReadOnlyBody());
+        mapMessage.setObject("name", "value");
+    }
+
+    /**
+     * Test that calling {@link JmsMapMessage#clearBody()} clears the underlying message body
+     * map.
+     */
+    @Test
+    public void testClearBodyClearsUnderlyingMessageMap() throws Exception {
+        JmsMapMessageFacade facade = new JmsDefaultMapMessageFacade();
+        String myKey1 = "key1";
+        facade.put(myKey1, "value1");
+
+        JmsMapMessage mapMessage = new JmsMapMessage(facade);
+
+        assertTrue("key should exist: " + myKey1, mapMessage.itemExists(myKey1));
+        mapMessage.clearBody();
+        assertTrue("expected map to be emptied", facade.isEmpty());
+        assertFalse("key should not exist", mapMessage.itemExists(myKey1));
+    }
+
+    /**
+     * When a map entry is not set, the behaviour of JMS specifies that it is equivalent to a
+     * null value, and the accessors should either return null, throw NPE, or behave in the same
+     * fashion as <primitive>.valueOf(String).
+     *
+     * Test that this is the case.
+     */
+    @Test
+    public void testGetMissingMapEntryResultsInExpectedBehaviour() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "does_not_exist";
+
+        // expect null
+        assertNull(mapMessage.getBytes(name));
+        assertNull(mapMessage.getString(name));
+
+        // expect false from Boolean.valueOf(null).
+        assertFalse(mapMessage.getBoolean(name));
+
+        // expect an NFE from the primitive integral <type>.valueOf(null) conversions
+        assertGetMapEntryThrowsNumberFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsNumberFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsNumberFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsNumberFormatException(mapMessage, name, Long.class);
+
+        // expect an NPE from the primitive float, double, and char <type>.valuleOf(null)
+        // conversions
+        assertGetMapEntryThrowsNullPointerException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsNullPointerException(mapMessage, name, Double.class);
+        assertGetMapEntryThrowsNullPointerException(mapMessage, name, Character.class);
+    }
+
+    // ======= object =========
+
+    /**
+     * Test that the {@link JmsMapMessage#setObject(String, Object)} method rejects Objects of
+     * unexpected types
+     */
+    @Test(expected=MessageFormatException.class)
+    public void testSetObjectWithIllegalTypeThrowsMFE() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+        mapMessage.setObject("myPKey", new Exception());
+    }
+
+    @Test
+    public void testSetGetObject() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+        String keyName = "myProperty";
+
+        Object entryValue = null;
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Boolean.valueOf(false);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Byte.valueOf((byte) 1);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Short.valueOf((short) 2);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Integer.valueOf(3);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Long.valueOf(4);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Float.valueOf(5.01F);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Double.valueOf(6.01);
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = "string";
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        entryValue = Character.valueOf('c');
+        mapMessage.setObject(keyName, entryValue);
+        assertEquals(entryValue, mapMessage.getObject(keyName));
+
+        byte[] bytes = new byte[] { (byte) 1, (byte) 0, (byte) 1 };
+        mapMessage.setObject(keyName, bytes);
+        Object retrieved = mapMessage.getObject(keyName);
+        assertTrue(retrieved instanceof byte[]);
+        assertTrue(Arrays.equals(bytes, (byte[]) retrieved));
+    }
+
+    // ======= Strings =========
+
+    @Test
+    public void testSetGetString() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        // null value
+        String name = "myNullString";
+        String value = null;
+
+        assertFalse(mapMessage.itemExists(name));
+        mapMessage.setString(name, value);
+        assertTrue(mapMessage.itemExists(name));
+        assertEquals(value, mapMessage.getString(name));
+
+        // non-null value
+        name = "myName";
+        value = "myValue";
+
+        assertFalse(mapMessage.itemExists(name));
+        mapMessage.setString(name, value);
+        assertTrue(mapMessage.itemExists(name));
+        assertEquals(value, mapMessage.getString(name));
+    }
+
+    /**
+     * Set a String, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testSetStringGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myStringName";
+        String value;
+
+        // boolean
+        value = "true";
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Boolean.valueOf(value), Boolean.class);
+
+        // byte
+        value = String.valueOf(Byte.MAX_VALUE);
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Byte.valueOf(value), Byte.class);
+
+        // short
+        value = String.valueOf(Short.MAX_VALUE);
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Short.valueOf(value), Short.class);
+
+        // int
+        value = String.valueOf(Integer.MAX_VALUE);
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Integer.valueOf(value), Integer.class);
+
+        // long
+        value = String.valueOf(Long.MAX_VALUE);
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Long.valueOf(value), Long.class);
+
+        // float
+        value = String.valueOf(Float.MAX_VALUE);
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Float.valueOf(value), Float.class);
+
+        // double
+        value = String.valueOf(Double.MAX_VALUE);
+        mapMessage.setString(name, value);
+        assertGetMapEntryEquals(mapMessage, name, Double.valueOf(value), Double.class);
+    }
+
+    /**
+     * Set a String, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetStringGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        String value = "myStringValue";
+
+        mapMessage.setString(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+    }
+
+    // ======= boolean =========
+
+    /**
+     * Set a boolean, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testSetBooleanGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        boolean value = true;
+
+        mapMessage.setBoolean(name, value);
+        assertEquals("value not as expected", value, mapMessage.getBoolean(name));
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a boolean, then retrieve it as all of the illegal type combinations to verify it
+     * fails as expected
+     */
+    @Test
+    public void testSetBooleanGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        boolean value = true;
+
+        mapMessage.setBoolean(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Long.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+    // ======= byte =========
+
+    /**
+     * Set a byte, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testSetByteGetLegalProperty() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte value = (byte) 1;
+
+        mapMessage.setByte(name, value);
+        assertEquals(value, mapMessage.getByte(name));
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+        assertGetMapEntryEquals(mapMessage, name, Short.valueOf(value), Short.class);
+        assertGetMapEntryEquals(mapMessage, name, Integer.valueOf(value), Integer.class);
+        assertGetMapEntryEquals(mapMessage, name, Long.valueOf(value), Long.class);
+    }
+
+    /**
+     * Set a byte, then retrieve it as all of the illegal type combinations to verify it is
+     * fails as expected
+     */
+    @Test
+    public void testSetByteGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte value = (byte) 1;
+
+        mapMessage.setByte(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+    // ======= short =========
+
+    /**
+     * Set a short, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testSetShortGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        short value = (short) 1;
+
+        mapMessage.setShort(name, value);
+        assertEquals(value, mapMessage.getShort(name));
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+        assertGetMapEntryEquals(mapMessage, name, Integer.valueOf(value), Integer.class);
+        assertGetMapEntryEquals(mapMessage, name, Long.valueOf(value), Long.class);
+    }
+
+    /**
+     * Set a short, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetShortGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        short value = (short) 1;
+
+        mapMessage.setShort(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+    // ======= int =========
+
+    /**
+     * Set an int, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testSetIntGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        int value = 1;
+
+        mapMessage.setInt(name, value);
+        assertEquals(value, mapMessage.getInt(name));
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+        assertGetMapEntryEquals(mapMessage, name, Long.valueOf(value), Long.class);
+    }
+
+    /**
+     * Set an int, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetIntGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        int value = 1;
+
+        mapMessage.setInt(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+    // ======= long =========
+
+    /**
+     * Set a long, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testSetLongGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        long value = Long.MAX_VALUE;
+
+        mapMessage.setLong(name, value);
+        assertEquals(value, mapMessage.getLong(name));
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set an long, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetLongGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        long value = Long.MAX_VALUE;
+
+        mapMessage.setLong(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+    // ======= float =========
+
+    /**
+     * Set a float, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testSetFloatGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        float value = Float.MAX_VALUE;
+
+        mapMessage.setFloat(name, value);
+        assertEquals(value, mapMessage.getFloat(name), 0.0);
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+        assertGetMapEntryEquals(mapMessage, name, Double.valueOf(value), Double.class);
+    }
+
+    /**
+     * Set a float, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetFloatGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        float value = Float.MAX_VALUE;
+
+        mapMessage.setFloat(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Long.class);
+    }
+
+    // ======= double =========
+
+    /**
+     * Set a double, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testSetDoubleGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        double value = Double.MAX_VALUE;
+
+        mapMessage.setDouble(name, value);
+        assertEquals(value, mapMessage.getDouble(name), 0.0);
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a double, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetDoubleGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        double value = Double.MAX_VALUE;
+
+        mapMessage.setDouble(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Long.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+    }
+
+    // ======= character =========
+
+    /**
+     * Set a char, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testSetCharGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        char value = 'c';
+
+        mapMessage.setChar(name, value);
+        assertEquals(value, mapMessage.getChar(name));
+
+        assertGetMapEntryEquals(mapMessage, name, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a char, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testSetCharGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        char value = 'c';
+
+        mapMessage.setChar(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, byte[].class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Long.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+    // ========= bytes ========
+
+    /**
+     * Set bytes, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testSetBytesGetLegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte[] value = "myBytes".getBytes();
+
+        mapMessage.setBytes(name, value);
+        assertTrue(Arrays.equals(value, mapMessage.getBytes(name)));
+    }
+
+    /**
+     * Set bytes, then retrieve it as all of the illegal type combinations to verify it fails as
+     * expected
+     */
+    @Test
+    public void testSetBytesGetIllegal() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte[] value = "myBytes".getBytes();
+
+        mapMessage.setBytes(name, value);
+
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Character.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, String.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Boolean.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Byte.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Short.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Integer.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Long.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Float.class);
+        assertGetMapEntryThrowsMessageFormatException(mapMessage, name, Double.class);
+    }
+
+//  TODO - This is a test that should be moved to the Facade test for the AMQP message facades.
+//
+//    /**
+//     * Verify that for a message received with an AmqpValue containing a Map with a Binary entry
+//     * value, we are able to read it back as a byte[].
+//     */
+//    @Test
+//    public void testReceivedMapWithBinaryEntryReturnsByteArray() throws Exception {
+//        String myKey1 = "key1";
+//        String bytesSource = "myBytesAmqpValue";
+//
+//        Map<String, Object> origMap = new HashMap<String, Object>();
+//        byte[] bytes = bytesSource.getBytes();
+//        origMap.put(myKey1, new Binary(bytes));
+//
+//        org.apache.qpid.proton.codec.Data payloadData = new DataImpl();
+//        payloadData.putDescribedType(new AmqpValueDescribedType(origMap));
+//        Binary b = payloadData.encode();
+//
+//        System.out.println("Using encoded AMQP message payload: " + b);
+//
+//        Message message = Proton.message();
+//        int decoded = message.decode(b.getArray(), b.getArrayOffset(), b.getLength());
+//        assertEquals(decoded, b.getLength());
+//
+//        AmqpMapMessage amqpMapMessage = new AmqpMapMessage(message, _mockDelivery, _mockAmqpConnection);
+//
+//        JmsMapMessage mapMessage = new JmsMapMessage(amqpMapMessage, _mockSessionImpl, _mockConnectionImpl, null);
+//
+//        // retrieve the bytes using getBytes, check they match expectation
+//        byte[] receivedBytes = mapMessage.getBytes(myKey1);
+//        assertTrue(Arrays.equals(bytes, receivedBytes));
+//
+//        // retrieve the bytes using getObject, check they match expectation
+//        Object o = mapMessage.getObject(myKey1);
+//        assertTrue(o instanceof byte[]);
+//        assertTrue(Arrays.equals(bytes, (byte[]) o));
+//    }
+
+    /**
+     * Verify that setting bytes takes a copy of the array. Set bytes, then modify them, then
+     * retrieve the map entry and verify the two differ.
+     */
+    @Test
+    public void testSetBytesTakesSnapshot() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte[] orig = "myBytes".getBytes();
+        byte[] copy = Arrays.copyOf(orig, orig.length);
+
+        // set the original bytes
+        mapMessage.setBytes(name, orig);
+
+        // corrupt the original bytes
+        orig[0] = (byte) 0;
+
+        // verify retrieving the bytes still matches the copy but not the original array
+        byte[] retrieved = mapMessage.getBytes(name);
+        assertFalse(Arrays.equals(orig, retrieved));
+        assertTrue(Arrays.equals(copy, retrieved));
+    }
+
+    /**
+     * Verify that getting bytes returns a copy of the array. Set bytes, then get them, modify
+     * the retrieved value, then get them again and verify the two differ.
+     */
+    @Test
+    public void testGetBytesReturnsSnapshot() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte[] orig = "myBytes".getBytes();
+
+        // set the original bytes
+        mapMessage.setBytes(name, orig);
+
+        // retrieve them
+        byte[] retrieved1 = mapMessage.getBytes(name);
+        ;
+
+        // corrupt the retrieved bytes
+        retrieved1[0] = (byte) 0;
+
+        // verify retrieving the bytes again still matches the original array, but not the
+        // previously retrieved (and now corrupted) bytes.
+        byte[] retrieved2 = mapMessage.getBytes(name);
+        assertTrue(Arrays.equals(orig, retrieved2));
+        assertFalse(Arrays.equals(retrieved1, retrieved2));
+    }
+
+    /**
+     * Verify that setting bytes takes a copy of the array. Set bytes, then modify them, then
+     * retrieve the map entry and verify the two differ.
+     */
+    @Test
+    public void testSetBytesWithOffsetAndLength() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        byte[] orig = "myBytesAll".getBytes();
+
+        // extract the segment containing 'Bytes'
+        int offset = 2;
+        int length = 5;
+        byte[] segment = Arrays.copyOfRange(orig, offset, offset + length);
+
+        // set the same section from the original bytes
+        mapMessage.setBytes(name, orig, offset, length);
+
+        // verify the retrieved bytes from the map match the segment but not the full original
+        // array
+        byte[] retrieved = mapMessage.getBytes(name);
+        assertFalse(Arrays.equals(orig, retrieved));
+        assertTrue(Arrays.equals(segment, retrieved));
+    }
+
+    @Test
+    public void testSetBytesWithNull() throws Exception {
+        JmsMapMessage mapMessage = factory.createMapMessage();
+
+        String name = "myName";
+        mapMessage.setBytes(name, null);
+        assertNull(mapMessage.getBytes(name));
+    }
+
+    // ========= utility methods ========
+
+    private void assertGetMapEntryEquals(JmsMapMessage testMessage, String name, Object expectedValue, Class<?> clazz) throws JMSException {
+        Object actualValue = getMapEntryUsingTypeMethod(testMessage, name, clazz);
+        assertEquals(expectedValue, actualValue);
+    }
+
+    private void assertGetMapEntryThrowsMessageFormatException(JmsMapMessage testMessage, String name, Class<?> clazz) throws JMSException {
+        try {
+            getMapEntryUsingTypeMethod(testMessage, name, clazz);
+            fail("expected exception to be thrown");
+        } catch (MessageFormatException jmsMFE) {
+            // expected
+        }
+    }
+
+    private void assertGetMapEntryThrowsNumberFormatException(JmsMapMessage testMessage, String name, Class<?> clazz) throws JMSException {
+        try {
+            getMapEntryUsingTypeMethod(testMessage, name, clazz);
+            fail("expected exception to be thrown");
+        } catch (NumberFormatException nfe) {
+            // expected
+        }
+    }
+
+    private void assertGetMapEntryThrowsNullPointerException(JmsMapMessage testMessage, String name, Class<?> clazz) throws JMSException {
+        try {
+            getMapEntryUsingTypeMethod(testMessage, name, clazz);
+            fail("expected exception to be thrown");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+    }
+
+    private Object getMapEntryUsingTypeMethod(JmsMapMessage testMessage, String name, Class<?> clazz) throws JMSException {
+        if (clazz == Boolean.class) {
+            return testMessage.getBoolean(name);
+        } else if (clazz == Byte.class) {
+            return testMessage.getByte(name);
+        } else if (clazz == Character.class) {
+            return testMessage.getChar(name);
+        } else if (clazz == Short.class) {
+            return testMessage.getShort(name);
+        } else if (clazz == Integer.class) {
+            return testMessage.getInt(name);
+        } else if (clazz == Long.class) {
+            return testMessage.getLong(name);
+        } else if (clazz == Float.class) {
+            return testMessage.getFloat(name);
+        } else if (clazz == Double.class) {
+            return testMessage.getDouble(name);
+        } else if (clazz == String.class) {
+            return testMessage.getString(name);
+        } else if (clazz == byte[].class) {
+            return testMessage.getBytes(name);
+        } else {
+            throw new RuntimeException("Unexpected entry type class");
+        }
+    }
+}


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


[25/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableListener.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableListener.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableListener.java
new file mode 100644
index 0000000..880960f
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageAvailableListener.java
@@ -0,0 +1,35 @@
+/**
+ * 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.jms;
+
+import javax.jms.MessageConsumer;
+
+
+/**
+ * Internal JmsMessage available listener.
+ */
+public interface JmsMessageAvailableListener {
+
+    /**
+     * Called when a Message is available to be received by a client
+     *
+     * @param consumer
+     *        the MessageConsumer instance that has message available.
+     */
+    public void onMessageAvailable(MessageConsumer consumer);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
new file mode 100644
index 0000000..07cba2a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageConsumer.java
@@ -0,0 +1,509 @@
+/**
+ * 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.jms;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFuture;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+import org.apache.qpid.jms.util.FifoMessageQueue;
+import org.apache.qpid.jms.util.MessageQueue;
+import org.apache.qpid.jms.util.PriorityMessageQueue;
+
+/**
+ * implementation of a JMS Message Consumer
+ */
+public class JmsMessageConsumer implements MessageConsumer, JmsMessageAvailableConsumer, JmsMessageDispatcher {
+
+    protected final JmsSession session;
+    protected final JmsConnection connection;
+    protected JmsConsumerInfo consumerInfo;
+    protected final int acknowledgementMode;
+    protected final AtomicBoolean closed = new AtomicBoolean();
+    protected boolean started;
+    protected MessageListener messageListener;
+    protected JmsMessageAvailableListener availableListener;
+    protected final MessageQueue messageQueue;
+    protected final Lock lock = new ReentrantLock();
+    protected final AtomicBoolean suspendedConnection = new AtomicBoolean();
+    protected final AtomicBoolean delivered = new AtomicBoolean();
+
+    /**
+     * Create a non-durable MessageConsumer
+     *
+     * @param consumerId
+     * @param session
+     * @param destination
+     * @param selector
+     * @param noLocal
+     * @throws JMSException
+     */
+    protected JmsMessageConsumer(JmsConsumerId consumerId, JmsSession session, JmsDestination destination,
+        String selector, boolean noLocal) throws JMSException {
+        this(consumerId, session, destination, null, selector, noLocal);
+    }
+
+    /**
+     * Create a MessageConsumer which could be durable.
+     *
+     * @param consumerId
+     * @param session
+     * @param destination
+     * @param name
+     * @param selector
+     * @param noLocal
+     * @throws JMSException
+     */
+    protected JmsMessageConsumer(JmsConsumerId consumerId, JmsSession session, JmsDestination destination,
+                                 String name, String selector, boolean noLocal) throws JMSException {
+        this.session = session;
+        this.connection = session.getConnection();
+        this.acknowledgementMode = session.acknowledgementMode();
+
+        if (connection.isMessagePrioritySupported()) {
+            this.messageQueue = new PriorityMessageQueue();
+        } else {
+            this.messageQueue = new FifoMessageQueue();
+        }
+
+        JmsPrefetchPolicy policy = this.connection.getPrefetchPolicy();
+
+        this.consumerInfo = new JmsConsumerInfo(consumerId);
+        this.consumerInfo.setClientId(connection.getClientID());
+        this.consumerInfo.setSelector(selector);
+        this.consumerInfo.setSubscriptionName(name);
+        this.consumerInfo.setDestination(destination);
+        this.consumerInfo.setAcknowledgementMode(acknowledgementMode);
+        this.consumerInfo.setNoLocal(noLocal);
+        this.consumerInfo.setBrowser(isBrowser());
+        this.consumerInfo.setPrefetchSize(getConfiguredPrefetch(destination, policy));
+
+        try {
+            this.consumerInfo = session.getConnection().createResource(consumerInfo);
+        } catch (JMSException ex) {
+            throw ex;
+        }
+    }
+
+    public void init() throws JMSException {
+        session.add(this);
+        try {
+            session.getConnection().startResource(consumerInfo);
+        } catch (JMSException ex) {
+            session.remove(this);
+            throw ex;
+        }
+    }
+
+    /**
+     * @throws JMSException
+     * @see javax.jms.MessageConsumer#close()
+     */
+    @Override
+    public void close() throws JMSException {
+        if (!closed.get()) {
+            if (delivered.get() && session.getTransactionContext().isInTransaction()) {
+                session.getTransactionContext().addSynchronization(new JmsTxSynchronization() {
+                    @Override
+                    public void afterCommit() throws Exception {
+                        doClose();
+                    }
+
+                    @Override
+                    public void afterRollback() throws Exception {
+                        doClose();
+                    }
+                });
+            } else {
+                doClose();
+            }
+        }
+    }
+
+    /**
+     * Called to initiate shutdown of Producer resources and request that the remote
+     * peer remove the registered producer.
+     *
+     * @throws JMSException
+     */
+    protected void doClose() throws JMSException {
+        shutdown();
+        this.connection.destroyResource(consumerInfo);
+    }
+
+    /**
+     * Called to release all producer resources without requiring a destroy request
+     * to be sent to the remote peer.  This is most commonly needed when the parent
+     * Session is closing.
+     *
+     * @throws JMSException
+     */
+    protected void shutdown() throws JMSException {
+        if (closed.compareAndSet(false, true)) {
+            this.session.remove(this);
+        }
+    }
+
+    /**
+     * @return a Message or null if closed during the operation
+     * @throws JMSException
+     * @see javax.jms.MessageConsumer#receive()
+     */
+    @Override
+    public Message receive() throws JMSException {
+        checkClosed();
+        checkMessageListener();
+        sendPullCommand(0);
+
+        try {
+            return copy(ack(this.messageQueue.dequeue(-1)));
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    /**
+     * @param timeout
+     * @return a Message or null
+     * @throws JMSException
+     * @see javax.jms.MessageConsumer#receive(long)
+     */
+    @Override
+    public Message receive(long timeout) throws JMSException {
+        checkClosed();
+        checkMessageListener();
+        sendPullCommand(timeout);
+
+        if (timeout > 0) {
+            try {
+                return copy(ack(this.messageQueue.dequeue(timeout)));
+            } catch (InterruptedException e) {
+                throw JmsExceptionSupport.create(e);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @return a Message or null
+     * @throws JMSException
+     * @see javax.jms.MessageConsumer#receiveNoWait()
+     */
+    @Override
+    public Message receiveNoWait() throws JMSException {
+        checkClosed();
+        checkMessageListener();
+        sendPullCommand(-1);
+
+        return copy(ack(this.messageQueue.dequeueNoWait()));
+    }
+
+    protected void checkClosed() throws IllegalStateException {
+        if (this.closed.get()) {
+            throw new IllegalStateException("The MessageConsumer is closed");
+        }
+    }
+
+    JmsMessage copy(final JmsInboundMessageDispatch envelope) throws JMSException {
+        if (envelope == null || envelope.getMessage() == null) {
+            return null;
+        }
+        return envelope.getMessage().copy();
+    }
+
+    JmsInboundMessageDispatch ack(final JmsInboundMessageDispatch envelope) throws JMSException {
+        if (envelope != null && envelope.getMessage() != null) {
+            JmsMessage message = envelope.getMessage();
+            if (message.getAcknowledgeCallback() != null || session.isTransacted()) {
+                // Message has been received by the app.. expand the credit
+                // window so that we receive more messages.
+                session.acknowledge(envelope, ACK_TYPE.DELIVERED);
+            } else {
+                doAck(envelope);
+            }
+            // Tags that we have delivered and can't close if in a TX Session.
+            delivered.set(true);
+        }
+        return envelope;
+    }
+
+    private void doAck(final JmsInboundMessageDispatch envelope) throws JMSException {
+        checkClosed();
+        try {
+            session.acknowledge(envelope, ACK_TYPE.CONSUMED);
+        } catch (JMSException ex) {
+            session.onException(ex);
+            throw ex;
+        }
+    }
+
+    /**
+     * Called from the session when a new Message has been dispatched to this Consumer
+     * from the connection.
+     *
+     * @param facade
+     *        the newly arrived message.
+     */
+    @Override
+    public void onMessage(final JmsInboundMessageDispatch envelope) {
+        lock.lock();
+        try {
+            if (acknowledgementMode == Session.CLIENT_ACKNOWLEDGE) {
+                envelope.getMessage().setAcknowledgeCallback(new Callable<Void>() {
+                    @Override
+                    public Void call() throws Exception {
+                        if (session.isClosed()) {
+                            throw new javax.jms.IllegalStateException("Session closed.");
+                        }
+                        session.acknowledge();
+                        return null;
+                    }
+                });
+            }
+            this.messageQueue.enqueue(envelope);
+        } finally {
+            lock.unlock();
+        }
+
+        if (this.messageListener != null && this.started) {
+            session.getExecutor().execute(new Runnable() {
+                @Override
+                public void run() {
+                    JmsInboundMessageDispatch envelope;
+                    while (session.isStarted() && (envelope = messageQueue.dequeueNoWait()) != null) {
+                        try {
+                            messageListener.onMessage(copy(ack(envelope)));
+                        } catch (Exception e) {
+                            session.getConnection().onException(e);
+                        }
+                    }
+                }
+            });
+        } else {
+            if (availableListener != null) {
+                availableListener.onMessageAvailable(this);
+            }
+        }
+    }
+
+    public void start() {
+        lock.lock();
+        try {
+            this.started = true;
+            this.messageQueue.start();
+            drainMessageQueueToListener();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void stop() {
+        lock.lock();
+        try {
+            this.started = false;
+            this.messageQueue.stop();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    void drainMessageQueueToListener() {
+        MessageListener listener = this.messageListener;
+        if (listener != null) {
+            if (!this.messageQueue.isEmpty()) {
+                List<JmsInboundMessageDispatch> drain = this.messageQueue.removeAll();
+                for (JmsInboundMessageDispatch envelope : drain) {
+                    try {
+                        listener.onMessage(copy(ack(envelope)));
+                    } catch (Exception e) {
+                        session.getConnection().onException(e);
+                    }
+                }
+                drain.clear();
+            }
+        }
+    }
+
+    /**
+     * @return the id
+     */
+    public JmsConsumerId getConsumerId() {
+        return this.consumerInfo.getConsumerId();
+    }
+
+    /**
+     * @return the Destination
+     */
+    public JmsDestination getDestination() {
+        return this.consumerInfo.getDestination();
+    }
+
+    @Override
+    public MessageListener getMessageListener() throws JMSException {
+        checkClosed();
+        return this.messageListener;
+    }
+
+    /**
+     * @param listener
+     * @throws JMSException
+     * @see javax.jms.MessageConsumer#setMessageListener(javax.jms.MessageListener)
+     */
+    @Override
+    public void setMessageListener(MessageListener listener) throws JMSException {
+        checkClosed();
+        if (consumerInfo.getPrefetchSize() == 0) {
+            throw new JMSException("Illegal prefetch size of zero. This setting is not supported" +
+                                   "for asynchronous consumers please set a value of at least 1");
+        }
+        this.messageListener = listener;
+        drainMessageQueueToListener();
+    }
+
+    /**
+     * @return the Message Selector
+     * @throws JMSException
+     * @see javax.jms.MessageConsumer#getMessageSelector()
+     */
+    @Override
+    public String getMessageSelector() throws JMSException {
+        checkClosed();
+        return this.consumerInfo.getSelector();
+    }
+
+    /**
+     * Gets the configured prefetch size for this consumer.
+     * @return the prefetch size configuration for this consumer.
+     */
+    public int getPrefetchSize() {
+        return this.consumerInfo.getPrefetchSize();
+    }
+
+    protected void checkMessageListener() throws JMSException {
+        session.checkMessageListener();
+    }
+
+    boolean hasMessageListener() {
+        return this.messageListener != null;
+    }
+
+    boolean isUsingDestination(JmsDestination destination) {
+        return this.consumerInfo.getDestination().equals(destination);
+    }
+
+    protected int getMessageQueueSize() {
+        return this.messageQueue.size();
+    }
+
+    public boolean getNoLocal() throws IllegalStateException {
+        return this.consumerInfo.isNoLocal();
+    }
+
+    public boolean isDurableSubscription() {
+        return false;
+    }
+
+    public boolean isBrowser() {
+        return false;
+    }
+
+    @Override
+    public void setAvailableListener(JmsMessageAvailableListener availableListener) {
+        this.availableListener = availableListener;
+    }
+
+    @Override
+    public JmsMessageAvailableListener getAvailableListener() {
+        return availableListener;
+    }
+
+    protected void onConnectionInterrupted() {
+        messageQueue.clear();
+    }
+
+    protected void onConnectionRecovery(Provider provider) throws Exception {
+        ProviderFuture request = new ProviderFuture();
+        provider.create(consumerInfo, request);
+        request.sync();
+    }
+
+    protected void onConnectionRecovered(Provider provider) throws Exception {
+        ProviderFuture request = new ProviderFuture();
+        provider.start(consumerInfo, request);
+        request.sync();
+    }
+
+    protected void onConnectionRestored() {
+    }
+
+    /**
+     * Triggers a pull request from the connected Provider.  An attempt is made to set
+     * a timeout on the pull request however some providers will not honor this value
+     * and the pull will remain active until a message is dispatched.
+     *
+     * The timeout value can be one of:
+     *
+     *  < 0 to indicate that the request should expire immediately if no message.
+     *  = 0 to indicate that the request should never time out.
+     *  > 1 to indicate that the request should expire after the given time in milliseconds.
+     *
+     * @param timeout
+     *        The amount of time the pull request should remain valid.
+     */
+    protected void sendPullCommand(long timeout) throws JMSException {
+        if (messageQueue.isEmpty() && (getPrefetchSize() == 0 || isBrowser())) {
+            connection.pull(getConsumerId(), timeout);
+        }
+    }
+
+    private int getConfiguredPrefetch(JmsDestination destination, JmsPrefetchPolicy policy) {
+        int prefetch = 0;
+        if (destination.isTopic()) {
+            if (isDurableSubscription()) {
+                prefetch = policy.getDurableTopicPrefetch();
+            } else {
+                prefetch = policy.getTopicPrefetch();
+            }
+        } else {
+            if (isBrowser()) {
+                prefetch = policy.getQueueBrowserPrefetch();
+            } else {
+                prefetch = policy.getQueuePrefetch();
+            }
+        }
+
+        return prefetch;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageDispatcher.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageDispatcher.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageDispatcher.java
new file mode 100644
index 0000000..602e8b0
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageDispatcher.java
@@ -0,0 +1,31 @@
+/**
+ * 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.jms;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+
+public interface JmsMessageDispatcher {
+
+    /**
+     * Called when a new Message delivery is in progress.
+     *
+     * @param envelope
+     *        the incoming message dispatch information.
+     */
+    void onMessage(JmsInboundMessageDispatch envelope);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageProducer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageProducer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageProducer.java
new file mode 100644
index 0000000..4d09c04
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsMessageProducer.java
@@ -0,0 +1,334 @@
+/**
+ * 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.jms;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.InvalidDestinationException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+
+import org.apache.qpid.jms.message.JmsMessageTransformation;
+import org.apache.qpid.jms.meta.JmsProducerId;
+import org.apache.qpid.jms.meta.JmsProducerInfo;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.ProviderFuture;
+
+/**
+ * Implementation of a Jms MessageProducer
+ */
+public class JmsMessageProducer implements MessageProducer {
+
+    protected final JmsSession session;
+    protected final JmsConnection connection;
+    protected JmsProducerInfo producerInfo;
+    protected final boolean flexibleDestination;
+    protected int deliveryMode = DeliveryMode.PERSISTENT;
+    protected int priority = Message.DEFAULT_PRIORITY;
+    protected long timeToLive = Message.DEFAULT_TIME_TO_LIVE;
+    protected final AtomicBoolean closed = new AtomicBoolean();
+    protected boolean disableMessageId;
+    protected boolean disableTimestamp;
+    protected final AtomicLong messageSequence = new AtomicLong();
+
+    protected JmsMessageProducer(JmsProducerId producerId, JmsSession session, JmsDestination destination) throws JMSException {
+        this.session = session;
+        this.connection = session.getConnection();
+        this.flexibleDestination = destination == null;
+        this.producerInfo = new JmsProducerInfo(producerId);
+        this.producerInfo.setDestination(destination);
+        this.producerInfo = session.getConnection().createResource(producerInfo);
+    }
+
+    /**
+     * Close the producer
+     *
+     * @throws JMSException
+     *
+     * @see javax.jms.MessageProducer#close()
+     */
+    @Override
+    public void close() throws JMSException {
+        if (!closed.get()) {
+            doClose();
+        }
+    }
+
+    /**
+     * Called to initiate shutdown of Producer resources and request that the remote
+     * peer remove the registered producer.
+     *
+     * @throws JMSException
+     */
+    protected void doClose() throws JMSException {
+        shutdown();
+        this.connection.destroyResource(producerInfo);
+    }
+
+    /**
+     * Called to release all producer resources without requiring a destroy request
+     * to be sent to the remote peer.  This is most commonly needed when the parent
+     * Session is closing.
+     *
+     * @throws JMSException
+     */
+    protected void shutdown() throws JMSException {
+        if (closed.compareAndSet(false, true)) {
+            this.session.remove(this);
+        }
+    }
+
+    /**
+     * @return the delivery mode
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#getDeliveryMode()
+     */
+    @Override
+    public int getDeliveryMode() throws JMSException {
+        checkClosed();
+        return this.deliveryMode;
+    }
+
+    /**
+     * @return the destination
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#getDestination()
+     */
+    @Override
+    public Destination getDestination() throws JMSException {
+        checkClosed();
+        return this.producerInfo.getDestination();
+    }
+
+    /**
+     * @return true if disableIds is set
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#getDisableMessageID()
+     */
+    @Override
+    public boolean getDisableMessageID() throws JMSException {
+        checkClosed();
+        return this.disableMessageId;
+    }
+
+    /**
+     * @return true if disable timestamp is set
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#getDisableMessageTimestamp()
+     */
+    @Override
+    public boolean getDisableMessageTimestamp() throws JMSException {
+        checkClosed();
+        return this.disableTimestamp;
+    }
+
+    /**
+     * @return the priority
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#getPriority()
+     */
+    @Override
+    public int getPriority() throws JMSException {
+        checkClosed();
+        return this.priority;
+    }
+
+    /**
+     * @return timeToLive
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#getTimeToLive()
+     */
+    @Override
+    public long getTimeToLive() throws JMSException {
+        checkClosed();
+        return this.timeToLive;
+    }
+
+    /**
+     * @param message
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#send(javax.jms.Message)
+     */
+    @Override
+    public void send(Message message) throws JMSException {
+        send(producerInfo.getDestination(), message, this.deliveryMode, this.priority, this.timeToLive);
+    }
+
+    /**
+     * @param destination
+     * @param message
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#send(javax.jms.Destination,
+     *      javax.jms.Message)
+     */
+    @Override
+    public void send(Destination destination, Message message) throws JMSException {
+        send(destination, message, this.deliveryMode, this.priority, this.timeToLive);
+    }
+
+    /**
+     * @param message
+     * @param deliveryMode
+     * @param priority
+     * @param timeToLive
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#send(javax.jms.Message, int, int, long)
+     */
+    @Override
+    public void send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+        send(producerInfo.getDestination(), message, deliveryMode, priority, timeToLive);
+    }
+
+    /**
+     * @param destination
+     * @param message
+     * @param deliveryMode
+     * @param priority
+     * @param timeToLive
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#send(javax.jms.Destination,
+     *      javax.jms.Message, int, int, long)
+     */
+    @Override
+    public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+        checkClosed();
+
+        if (destination == null) {
+            throw new InvalidDestinationException("Don't understand null destinations");
+        }
+        if (!this.flexibleDestination && !destination.equals(producerInfo.getDestination())) {
+            throw new UnsupportedOperationException("This producer can only send messages to: " + producerInfo.getDestination().getName());
+        }
+
+        this.session.send(this, destination, message, deliveryMode, priority, timeToLive, disableMessageId, disableTimestamp);
+    }
+
+    /**
+     * @param deliveryMode
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#setDeliveryMode(int)
+     */
+    @Override
+    public void setDeliveryMode(int deliveryMode) throws JMSException {
+        checkClosed();
+        this.deliveryMode = deliveryMode;
+    }
+
+    /**
+     * @param value
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#setDisableMessageID(boolean)
+     */
+    @Override
+    public void setDisableMessageID(boolean value) throws JMSException {
+        checkClosed();
+        this.disableMessageId = value;
+    }
+
+    /**
+     * @param value
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#setDisableMessageTimestamp(boolean)
+     */
+    @Override
+    public void setDisableMessageTimestamp(boolean value) throws JMSException {
+        checkClosed();
+        this.disableTimestamp = value;
+    }
+
+    /**
+     * @param defaultPriority
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#setPriority(int)
+     */
+    @Override
+    public void setPriority(int defaultPriority) throws JMSException {
+        checkClosed();
+        this.priority = defaultPriority;
+    }
+
+    /**
+     * @param timeToLive
+     * @throws JMSException
+     * @see javax.jms.MessageProducer#setTimeToLive(long)
+     */
+    @Override
+    public void setTimeToLive(long timeToLive) throws JMSException {
+        checkClosed();
+        this.timeToLive = timeToLive;
+    }
+
+    /**
+     * @param destination
+     *        the destination to set
+     * @throws JMSException
+     * @throws InvalidDestinationException
+     */
+    public void setDestination(Destination destination) throws JMSException {
+        if (destination == null) {
+            throw new InvalidDestinationException("Don't understand null destinations");
+        }
+        if (!this.flexibleDestination && !destination.equals(producerInfo.getDestination())) {
+            throw new UnsupportedOperationException("This producer can only send messages to: " + producerInfo.getDestination().getName());
+        }
+        producerInfo.setDestination(JmsMessageTransformation.transformDestination(session.getConnection(), destination));
+    }
+
+    /**
+     * @return the producer's assigned JmsProducerId.
+     */
+    protected JmsProducerId getProducerId() {
+        return this.producerInfo.getProducerId();
+    }
+
+    /**
+     * @return the next logical sequence for a Message sent from this Producer.
+     */
+    protected long getNextMessageSequence() {
+        return this.messageSequence.incrementAndGet();
+    }
+
+    protected void checkClosed() throws IllegalStateException {
+        if (closed.get()) {
+            throw new IllegalStateException("The MessageProducer is closed");
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Connection interruption handlers.
+    ////////////////////////////////////////////////////////////////////////////
+
+    protected void onConnectionInterrupted() {
+    }
+
+    protected void onConnectionRecovery(Provider provider) throws Exception {
+        ProviderFuture request = new ProviderFuture();
+        provider.create(producerInfo, request);
+        request.sync();
+    }
+
+    protected void onConnectionRecovered(Provider provider) throws Exception {
+    }
+
+    protected void onConnectionRestored() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsPrefetchPolicy.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsPrefetchPolicy.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsPrefetchPolicy.java
new file mode 100644
index 0000000..c1212f2
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsPrefetchPolicy.java
@@ -0,0 +1,181 @@
+/**
+ * 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.jms;
+
+import java.io.Serializable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Defines the prefetch message policies for different types of consumers
+ */
+public class JmsPrefetchPolicy extends Object implements Serializable {
+
+    private static final long serialVersionUID = 5298685386681646744L;
+
+    public static final int MAX_PREFETCH_SIZE = Short.MAX_VALUE;
+    public static final int DEFAULT_QUEUE_PREFETCH = 1000;
+    public static final int DEFAULT_QUEUE_BROWSER_PREFETCH = 500;
+    public static final int DEFAULT_DURABLE_TOPIC_PREFETCH = 100;
+    public static final int DEFAULT_TOPIC_PREFETCH = MAX_PREFETCH_SIZE;
+
+    private static final Logger LOG = LoggerFactory.getLogger(JmsPrefetchPolicy.class);
+
+    private int queuePrefetch;
+    private int queueBrowserPrefetch;
+    private int topicPrefetch;
+    private int durableTopicPrefetch;
+    private int maxPrefetchSize = MAX_PREFETCH_SIZE;
+
+    /**
+     * Initialize default prefetch policies
+     */
+    public JmsPrefetchPolicy() {
+        this.queuePrefetch = DEFAULT_QUEUE_PREFETCH;
+        this.queueBrowserPrefetch = DEFAULT_QUEUE_BROWSER_PREFETCH;
+        this.topicPrefetch = DEFAULT_TOPIC_PREFETCH;
+        this.durableTopicPrefetch = DEFAULT_DURABLE_TOPIC_PREFETCH;
+    }
+
+    /**
+     * Creates a new JmsPrefetchPolicy instance copied from the source policy.
+     *
+     * @param source
+     *      The policy instance to copy values from.
+     */
+    public JmsPrefetchPolicy(JmsPrefetchPolicy source) {
+        this.queuePrefetch = source.getQueuePrefetch();
+        this.queueBrowserPrefetch = source.getQueueBrowserPrefetch();
+        this.topicPrefetch = source.getTopicPrefetch();
+        this.durableTopicPrefetch = source.getDurableTopicPrefetch();
+    }
+
+    /**
+     * @return Returns the durableTopicPrefetch.
+     */
+    public int getDurableTopicPrefetch() {
+        return durableTopicPrefetch;
+    }
+
+    /**
+     * Sets the durable topic prefetch value, this value is limited by the max
+     * prefetch size setting.
+     *
+     * @param durableTopicPrefetch
+     *        The durableTopicPrefetch to set.
+     */
+    public void setDurableTopicPrefetch(int durableTopicPrefetch) {
+        this.durableTopicPrefetch = getMaxPrefetchLimit(durableTopicPrefetch);
+    }
+
+    /**
+     * @return Returns the queuePrefetch.
+     */
+    public int getQueuePrefetch() {
+        return queuePrefetch;
+    }
+
+    /**
+     * @param queuePrefetch
+     *        The queuePrefetch to set.
+     */
+    public void setQueuePrefetch(int queuePrefetch) {
+        this.queuePrefetch = getMaxPrefetchLimit(queuePrefetch);
+    }
+
+    /**
+     * @return Returns the queueBrowserPrefetch.
+     */
+    public int getQueueBrowserPrefetch() {
+        return queueBrowserPrefetch;
+    }
+
+    /**
+     * @param queueBrowserPrefetch
+     *        The queueBrowserPrefetch to set.
+     */
+    public void setQueueBrowserPrefetch(int queueBrowserPrefetch) {
+        this.queueBrowserPrefetch = getMaxPrefetchLimit(queueBrowserPrefetch);
+    }
+
+    /**
+     * @return Returns the topicPrefetch.
+     */
+    public int getTopicPrefetch() {
+        return topicPrefetch;
+    }
+
+    /**
+     * @param topicPrefetch
+     *        The topicPrefetch to set.
+     */
+    public void setTopicPrefetch(int topicPrefetch) {
+        this.topicPrefetch = getMaxPrefetchLimit(topicPrefetch);
+    }
+
+    /**
+     * Gets the currently configured max prefetch size value.
+     * @return the currently configured max prefetch value.
+     */
+    public int getMaxPrefetchSize() {
+        return maxPrefetchSize;
+    }
+
+    /**
+     * Sets the maximum prefetch size value.
+     *
+     * @param maxPrefetchSize
+     *        The maximum allowed value for any of the prefetch size options.
+     */
+    public void setMaxPrefetchSize(int maxPrefetchSize) {
+        this.maxPrefetchSize = maxPrefetchSize;
+    }
+
+    /**
+     * Sets the prefetch values for all options in this policy to the set limit.  If the value
+     * given is larger than the max prefetch value of this policy the new limit will be capped
+     * at the max prefetch value.
+     *
+     * @param prefetch
+     *      The prefetch value to apply to all prefetch limits.
+     */
+    public void setAll(int prefetch) {
+        this.durableTopicPrefetch = getMaxPrefetchLimit(prefetch);
+        this.queueBrowserPrefetch = getMaxPrefetchLimit(prefetch);
+        this.queuePrefetch = getMaxPrefetchLimit(prefetch);
+        this.topicPrefetch = getMaxPrefetchLimit(prefetch);
+    }
+
+    @Override
+    public boolean equals(Object object) {
+        if (object instanceof JmsPrefetchPolicy) {
+            JmsPrefetchPolicy other = (JmsPrefetchPolicy) object;
+            return this.queuePrefetch == other.queuePrefetch && this.queueBrowserPrefetch == other.queueBrowserPrefetch
+                && this.topicPrefetch == other.topicPrefetch && this.durableTopicPrefetch == other.durableTopicPrefetch;
+        }
+        return false;
+    }
+
+    private int getMaxPrefetchLimit(int value) {
+        int result = Math.min(value, maxPrefetchSize);
+        if (result < value) {
+            LOG.warn("maximum prefetch limit has been reset from " + value + " to " + MAX_PREFETCH_SIZE);
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueue.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueue.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueue.java
new file mode 100644
index 0000000..d9e397c
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueue.java
@@ -0,0 +1,49 @@
+/**
+ * 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.jms;
+
+import javax.jms.Queue;
+
+/**
+ * JMS Queue implementation
+ */
+public class JmsQueue extends JmsDestination implements Queue {
+
+    public JmsQueue() {
+        super(null, false, false);
+    }
+
+    public JmsQueue(String name) {
+        super(name, false, false);
+    }
+
+    @Override
+    public JmsQueue copy() {
+        final JmsQueue copy = new JmsQueue();
+        copy.setProperties(getProperties());
+        return copy;
+    }
+
+    /**
+     * @return name
+     * @see javax.jms.Queue#getQueueName()
+     */
+    @Override
+    public String getQueueName() {
+        return getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueBrowser.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueBrowser.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueBrowser.java
new file mode 100644
index 0000000..ce20d42
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueBrowser.java
@@ -0,0 +1,264 @@
+/**
+ * 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.jms;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Queue;
+import javax.jms.QueueBrowser;
+
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A client uses a <CODE>QueueBrowser</CODE> object to look at messages on a queue without
+ * removing them.
+ * <p/>
+ * <p/>
+ * The <CODE>getEnumeration</CODE> method returns a <CODE>
+ * java.util.Enumeration</CODE> that is used to scan the queue's messages. It may be an
+ * enumeration of the entire content of a queue, or it may contain only the messages matching a
+ * message selector.
+ * <p/>
+ * <p/>
+ * Messages may be arriving and expiring while the scan is done. The JMS API does not require
+ * the content of an enumeration to be a static snapshot of queue content. Whether these changes
+ * are visible or not depends on the JMS provider.
+ * <p/>
+ * <p/>
+ * A <CODE>QueueBrowser</CODE> can be created from either a <CODE>Session
+ * </CODE> or a <CODE>QueueSession</CODE>.
+ *
+ * @see javax.jms.Session#createBrowser
+ * @see javax.jms.QueueSession#createBrowser
+ * @see javax.jms.QueueBrowser
+ * @see javax.jms.QueueReceiver
+ */
+public class JmsQueueBrowser implements QueueBrowser, Enumeration<Message> {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsQueueBrowser.class);
+
+    private final JmsSession session;
+    private final JmsDestination destination;
+    private final String selector;
+
+    private JmsMessageConsumer consumer;
+    private final AtomicBoolean browseDone = new AtomicBoolean(false);
+
+    private Message next;
+    private final AtomicBoolean closed = new AtomicBoolean();
+    private final Object semaphore = new Object();
+
+    /**
+     * Constructor for an JmsQueueBrowser - used internally
+     *
+     * @param session
+     * @param id
+     * @param destination
+     * @param selector
+     * @throws javax.jms.JMSException
+     */
+    protected JmsQueueBrowser(JmsSession session, JmsDestination destination, String selector) throws JMSException {
+        this.session = session;
+        this.destination = destination;
+        this.selector = selector;
+    }
+
+    private void destroyConsumer() {
+        if (consumer == null) {
+            return;
+        }
+        try {
+            if (session.getTransacted()) {
+                session.commit();
+            }
+            consumer.close();
+            consumer = null;
+        } catch (JMSException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Gets an enumeration for browsing the current queue messages in the order they would be
+     * received.
+     *
+     * @return an enumeration for browsing the messages
+     * @throws javax.jms.JMSException
+     *         if the JMS provider fails to get the enumeration for this browser due to some
+     *         internal error.
+     */
+    @Override
+    public Enumeration<Message> getEnumeration() throws JMSException {
+        checkClosed();
+        if (consumer == null) {
+            consumer = createConsumer();
+        }
+        return this;
+    }
+
+    private void checkClosed() throws IllegalStateException {
+        if (closed.get()) {
+            throw new IllegalStateException("The Consumer is closed");
+        }
+    }
+
+    /**
+     * @return true if more messages to process
+     */
+    @Override
+    public boolean hasMoreElements() {
+        while (true) {
+            synchronized (this) {
+                if (consumer == null) {
+                    return false;
+                }
+            }
+
+            if (next == null) {
+                try {
+                    next = consumer.receiveNoWait();
+                } catch (JMSException e) {
+                    LOG.warn("Error while receive the next message: {}", e.getMessage());
+                    // TODO - Add client internal error listener.
+                    // this.session.connection.onClientInternalException(e);
+                }
+
+                if (next != null) {
+                    return true;
+                }
+            } else {
+                return true;
+            }
+
+            if (browseDone.get() || !session.isStarted()) {
+                destroyConsumer();
+                return false;
+            }
+
+            waitForMessage();
+        }
+    }
+
+    /**
+     * @return the next message if one exists
+     *
+     * @throws NoSuchElementException if no more elements are available.
+     */
+    @Override
+    public Message nextElement() {
+        synchronized (this) {
+            if (consumer == null) {
+                return null;
+            }
+        }
+
+        if (hasMoreElements()) {
+            Message message = next;
+            next = null;
+            return message;
+        }
+
+        if (browseDone.get() || !session.isStarted()) {
+            destroyConsumer();
+            return null;
+        }
+
+        throw new NoSuchElementException();
+    }
+
+    @Override
+    public void close() throws JMSException {
+        if (closed.compareAndSet(false, true)) {
+            browseDone.set(true);
+            destroyConsumer();
+        }
+    }
+
+    /**
+     * Gets the queue associated with this queue browser.
+     *
+     * @return the queue
+     * @throws javax.jms.JMSException
+     *         if the JMS provider fails to get the queue associated with this browser due to
+     *         some internal error.
+     */
+
+    @Override
+    public Queue getQueue() throws JMSException {
+        return (Queue) destination;
+    }
+
+    @Override
+    public String getMessageSelector() throws JMSException {
+        return selector;
+    }
+
+    /**
+     * Wait on a semaphore for a fixed amount of time for a message to come in.
+     */
+    protected void waitForMessage() {
+        try {
+            synchronized (semaphore) {
+                semaphore.wait(2000);
+            }
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    protected void notifyMessageAvailable() {
+        synchronized (semaphore) {
+            semaphore.notifyAll();
+        }
+    }
+
+    @Override
+    public String toString() {
+        JmsMessageConsumer consumer = this.consumer;
+        return "JmsQueueBrowser { value=" + (consumer != null ? consumer.getConsumerId() : "null") + " }";
+    }
+
+    private JmsMessageConsumer createConsumer() throws JMSException {
+        browseDone.set(false);
+        JmsMessageConsumer rc = new JmsMessageConsumer(session.getNextConsumerId(), session, destination, selector, false) {
+
+            @Override
+            public boolean isBrowser() {
+                return true;
+            }
+
+            @Override
+            public void onMessage(JmsInboundMessageDispatch envelope) {
+                if (envelope.getMessage() == null) {
+                    browseDone.set(true);
+                } else {
+                    super.onMessage(envelope);
+                }
+                notifyMessageAvailable();
+            }
+        };
+        rc.init();
+        return rc;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueConnection.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueConnection.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueConnection.java
new file mode 100644
index 0000000..39eadeb
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueConnection.java
@@ -0,0 +1,48 @@
+/**
+ * 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.jms;
+
+import javax.jms.ConnectionConsumer;
+import javax.jms.JMSException;
+import javax.jms.ServerSessionPool;
+import javax.jms.Topic;
+import javax.jms.TopicSession;
+
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.util.IdGenerator;
+
+public class JmsQueueConnection extends JmsConnection {
+
+    public JmsQueueConnection(String connectionId, Provider provider, IdGenerator clientIdGenerator) throws JMSException {
+        super(connectionId, provider, clientIdGenerator);
+    }
+
+    @Override
+    public TopicSession createTopicSession(boolean transacted, int acknowledgeMode) throws JMSException {
+        throw new javax.jms.IllegalStateException("Operation not supported by a QueueConnection");
+    }
+
+    @Override
+    public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        throw new javax.jms.IllegalStateException("Operation not supported by a QueueConnection");
+    }
+
+    @Override
+    public ConnectionConsumer createConnectionConsumer(Topic topic, String messageSelector, ServerSessionPool sessionPool, int maxMessages) throws JMSException {
+        throw new javax.jms.IllegalStateException("Operation not supported by a QueueConnection");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueReceiver.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueReceiver.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueReceiver.java
new file mode 100644
index 0000000..aa1da65
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueReceiver.java
@@ -0,0 +1,59 @@
+/**
+ * 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.jms;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Queue;
+import javax.jms.QueueReceiver;
+
+import org.apache.qpid.jms.meta.JmsConsumerId;
+
+/**
+ * Implementation of a JMS QueueReceiver
+ */
+public class JmsQueueReceiver extends JmsMessageConsumer implements QueueReceiver {
+
+    /**
+     * Constructor
+     *
+     * @param id
+     *      This receiver's assigned Id.
+     * @param session
+     *      The session that created this receiver.
+     * @param dest
+     *      The destination that this receiver listens on.
+     * @param selector
+     *      The selector used to filter messages for this receiver.
+     *
+     * @throws JMSException
+     */
+    protected JmsQueueReceiver(JmsConsumerId id, JmsSession session, JmsDestination dest, String selector) throws JMSException {
+        super(id, session, dest, selector, false);
+    }
+
+    /**
+     * @return the Queue
+     * @throws IllegalStateException
+     * @see javax.jms.QueueReceiver#getQueue()
+     */
+    @Override
+    public Queue getQueue() throws IllegalStateException {
+        checkClosed();
+        return (Queue) this.getDestination();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSender.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSender.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSender.java
new file mode 100644
index 0000000..c2276c8
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSender.java
@@ -0,0 +1,78 @@
+/**
+ * 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.jms;
+
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Queue;
+import javax.jms.QueueSender;
+
+import org.apache.qpid.jms.meta.JmsProducerId;
+
+/**
+ * Implementation of a Queue Sender
+ */
+public class JmsQueueSender extends JmsMessageProducer implements QueueSender {
+
+    /**
+     * Constructor
+     *
+     * @param id
+     * @param session
+     * @param destination
+     */
+    protected JmsQueueSender(JmsProducerId id, JmsSession session, JmsDestination destination) throws JMSException {
+        super(id, session, destination);
+    }
+
+    /**
+     * @return the Queue
+     * @throws IllegalStateException
+     * @see javax.jms.QueueSender#getQueue()
+     */
+    @Override
+    public Queue getQueue() throws IllegalStateException {
+        checkClosed();
+        return (Queue) this.producerInfo.getDestination();
+    }
+
+    /**
+     * @param queue
+     * @param message
+     * @throws JMSException
+     * @see javax.jms.QueueSender#send(javax.jms.Queue, javax.jms.Message)
+     */
+    @Override
+    public void send(Queue queue, Message message) throws JMSException {
+        super.send(queue, message);
+    }
+
+    /**
+     * @param queue
+     * @param message
+     * @param deliveryMode
+     * @param priority
+     * @param timeToLive
+     * @throws JMSException
+     * @see javax.jms.QueueSender#send(javax.jms.Queue, javax.jms.Message, int, int, long)
+     */
+    @Override
+    public void send(Queue queue, Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
+        super.send(message, deliveryMode, priority, timeToLive);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSession.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSession.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSession.java
new file mode 100644
index 0000000..274c0a7
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsQueueSession.java
@@ -0,0 +1,187 @@
+/**
+ * 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.jms;
+
+import javax.jms.Destination;
+import javax.jms.IllegalStateException;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.TemporaryTopic;
+import javax.jms.Topic;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSubscriber;
+
+import org.apache.qpid.jms.meta.JmsSessionId;
+
+/**
+ * JMS QueueSession implementation
+ */
+public class JmsQueueSession extends JmsSession {
+
+    protected JmsQueueSession(JmsConnection connection, JmsSessionId sessionId, int acknowledgementMode) throws JMSException {
+        super(connection, sessionId, acknowledgementMode);
+    }
+
+    @Override
+    public MessageConsumer createConsumer(Destination destination) throws JMSException {
+        if (destination instanceof Topic) {
+            throw new IllegalStateException("Operation not supported by a QueueSession");
+        }
+        return super.createConsumer(destination);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination,
+     *      java.lang.String)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination, String messageSelector) throws JMSException {
+        if (destination instanceof Topic) {
+            throw new IllegalStateException("Operation not supported by a QueueSession");
+        }
+        return super.createConsumer(destination, messageSelector);
+    }
+
+    /**
+     * @param destination
+     * @param messageSelector
+     * @param NoLocal
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createConsumer(javax.jms.Destination,
+     *      java.lang.String, boolean)
+     */
+    @Override
+    public MessageConsumer createConsumer(Destination destination, String messageSelector, boolean NoLocal) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param topic
+     * @param name
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createDurableSubscriber(javax.jms.Topic,
+     *      java.lang.String)
+     */
+    @Override
+    public TopicSubscriber createDurableSubscriber(Topic topic, String name) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param topic
+     * @param name
+     * @param messageSelector
+     * @param noLocal
+     * @return
+     * @throws IllegalStateException
+     * @throws JMSException
+     * @see javax.jms.Session#createDurableSubscriber(javax.jms.Topic,
+     *      java.lang.String, java.lang.String, boolean)
+     */
+    @Override
+    public TopicSubscriber createDurableSubscriber(Topic topic, String name, String messageSelector, boolean noLocal) throws IllegalStateException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param destination
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createProducer(javax.jms.Destination)
+     */
+    @Override
+    public MessageProducer createProducer(Destination destination) throws JMSException {
+        if (destination instanceof Topic) {
+            throw new IllegalStateException("Operation not supported by a QueueSession");
+        }
+        return super.createProducer(destination);
+    }
+
+    /**
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createTemporaryTopic()
+     */
+    @Override
+    public TemporaryTopic createTemporaryTopic() throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param topicName
+     * @return
+     * @throws JMSException
+     * @see javax.jms.Session#createTopic(java.lang.String)
+     */
+    @Override
+    public Topic createTopic(String topicName) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param name
+     * @throws JMSException
+     * @see javax.jms.Session#unsubscribe(java.lang.String)
+     */
+    @Override
+    public void unsubscribe(String name) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param topic
+     * @return
+     * @throws JMSException
+     * @see javax.jms.TopicSession#createPublisher(javax.jms.Topic)
+     */
+    @Override
+    public TopicPublisher createPublisher(Topic topic) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param topic
+     * @return
+     * @throws JMSException
+     * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic)
+     */
+    @Override
+    public TopicSubscriber createSubscriber(Topic topic) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+
+    /**
+     * @param topic
+     * @param messageSelector
+     * @param noLocal
+     * @return
+     * @throws JMSException
+     * @see javax.jms.TopicSession#createSubscriber(javax.jms.Topic,
+     *      java.lang.String, boolean)
+     */
+    @Override
+    public TopicSubscriber createSubscriber(Topic topic, String messageSelector, boolean noLocal) throws JMSException {
+        throw new IllegalStateException("Operation not supported by a QueueSession");
+    }
+}


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


[04/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsMessageIntegrityTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsMessageIntegrityTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsMessageIntegrityTest.java
new file mode 100644
index 0000000..f4b54a6
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsMessageIntegrityTest.java
@@ -0,0 +1,497 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.UUID;
+import java.util.Vector;
+
+import javax.jms.BytesMessage;
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Tests that messages sent and received don't lose data and have expected
+ * JMS Message property values.
+ */
+public class JmsMessageIntegrityTest extends AmqpTestSupport {
+
+    private Connection connection;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        connection = createAmqpConnection();
+    }
+
+    @Test
+    public void testTextMessage() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        {
+            TextMessage message = session.createTextMessage();
+            message.setText("Hi");
+            producer.send(message);
+        }
+        {
+            TextMessage message = (TextMessage)consumer.receive(1000);
+            assertNotNull(message);
+            assertEquals("Hi", message.getText());
+        }
+
+        assertNull(consumer.receiveNoWait());
+    }
+
+    @Test
+    public void testBytesMessageLength() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        {
+            BytesMessage message = session.createBytesMessage();
+            message.writeInt(1);
+            message.writeInt(2);
+            message.writeInt(3);
+            message.writeInt(4);
+            producer.send(message);
+        }
+        {
+            BytesMessage message = (BytesMessage)consumer.receive(1000);
+            assertNotNull(message);
+            assertEquals(16, message.getBodyLength());
+        }
+
+        assertNull(consumer.receiveNoWait());
+    }
+
+    @Test
+    public void testObjectMessage() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        UUID payload = UUID.randomUUID();
+
+        {
+            ObjectMessage message = session.createObjectMessage();
+            message.setObject(payload);
+            producer.send(message);
+        }
+        {
+            ObjectMessage message = (ObjectMessage)consumer.receive(1000);
+            assertNotNull(message);
+            assertEquals(payload, message.getObject());
+        }
+        assertNull(consumer.receiveNoWait());
+    }
+
+    @Test
+    public void testBytesMessage() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        {
+            BytesMessage message = session.createBytesMessage();
+            message.writeBoolean(true);
+            producer.send(message);
+        }
+        {
+            BytesMessage message = (BytesMessage)consumer.receive(1000);
+            assertNotNull(message);
+            assertTrue(message.readBoolean());
+
+            try {
+                message.readByte();
+                fail("Expected exception not thrown.");
+            } catch (MessageEOFException e) {
+            }
+        }
+        assertNull(consumer.receiveNoWait());
+    }
+
+    @Test
+    public void testStreamMessage() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        {
+            StreamMessage message = session.createStreamMessage();
+            message.writeString("This is a test to see how it works.");
+            producer.send(message);
+        }
+        {
+            StreamMessage message = (StreamMessage)consumer.receive(1000);
+            assertNotNull(message);
+
+            // Invalid conversion should throw exception and not move the stream position.
+            try {
+                message.readByte();
+                fail("Should have received NumberFormatException");
+            } catch (NumberFormatException e) {
+            }
+
+            assertEquals("This is a test to see how it works.", message.readString());
+
+            // Invalid conversion should throw exception and not move the stream position.
+            try {
+                message.readByte();
+                fail("Should have received MessageEOFException");
+            } catch (MessageEOFException e) {
+            }
+        }
+        assertNull(consumer.receiveNoWait());
+    }
+
+    @Test
+    public void testMapMessage() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        {
+            MapMessage message = session.createMapMessage();
+            message.setBoolean("boolKey", true);
+            producer.send(message);
+        }
+        {
+            MapMessage message = (MapMessage)consumer.receive(1000);
+            assertNotNull(message);
+            assertTrue(message.getBoolean("boolKey"));
+        }
+        assertNull(consumer.receiveNoWait());
+    }
+
+    static class ForeignMessage implements TextMessage {
+
+        public int deliveryMode;
+
+        private String messageId;
+        private long timestamp;
+        private String correlationId;
+        private Destination replyTo;
+        private Destination destination;
+        private boolean redelivered;
+        private String type;
+        private long expiration;
+        private int priority;
+        private String text;
+        private final HashMap<String, Object> props = new HashMap<String, Object>();
+
+        @Override
+        public String getJMSMessageID() throws JMSException {
+            return messageId;
+        }
+
+        @Override
+        public void setJMSMessageID(String arg0) throws JMSException {
+            messageId = arg0;
+        }
+
+        @Override
+        public long getJMSTimestamp() throws JMSException {
+            return timestamp;
+        }
+
+        @Override
+        public void setJMSTimestamp(long arg0) throws JMSException {
+            timestamp = arg0;
+        }
+
+        @Override
+        public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
+            return null;
+        }
+
+        @Override
+        public void setJMSCorrelationIDAsBytes(byte[] arg0) throws JMSException {
+        }
+
+        @Override
+        public void setJMSCorrelationID(String arg0) throws JMSException {
+            correlationId = arg0;
+        }
+
+        @Override
+        public String getJMSCorrelationID() throws JMSException {
+            return correlationId;
+        }
+
+        @Override
+        public Destination getJMSReplyTo() throws JMSException {
+            return replyTo;
+        }
+
+        @Override
+        public void setJMSReplyTo(Destination arg0) throws JMSException {
+            replyTo = arg0;
+        }
+
+        @Override
+        public Destination getJMSDestination() throws JMSException {
+            return destination;
+        }
+
+        @Override
+        public void setJMSDestination(Destination arg0) throws JMSException {
+            destination = arg0;
+        }
+
+        @Override
+        public int getJMSDeliveryMode() throws JMSException {
+            return deliveryMode;
+        }
+
+        @Override
+        public void setJMSDeliveryMode(int arg0) throws JMSException {
+            deliveryMode = arg0;
+        }
+
+        @Override
+        public boolean getJMSRedelivered() throws JMSException {
+            return redelivered;
+        }
+
+        @Override
+        public void setJMSRedelivered(boolean arg0) throws JMSException {
+            redelivered = arg0;
+        }
+
+        @Override
+        public String getJMSType() throws JMSException {
+            return type;
+        }
+
+        @Override
+        public void setJMSType(String arg0) throws JMSException {
+            type = arg0;
+        }
+
+        @Override
+        public long getJMSExpiration() throws JMSException {
+            return expiration;
+        }
+
+        @Override
+        public void setJMSExpiration(long arg0) throws JMSException {
+            expiration = arg0;
+        }
+
+        @Override
+        public int getJMSPriority() throws JMSException {
+            return priority;
+        }
+
+        @Override
+        public void setJMSPriority(int arg0) throws JMSException {
+            priority = arg0;
+        }
+
+        @Override
+        public void clearProperties() throws JMSException {
+        }
+
+        @Override
+        public boolean propertyExists(String arg0) throws JMSException {
+            return false;
+        }
+
+        @Override
+        public boolean getBooleanProperty(String arg0) throws JMSException {
+            return false;
+        }
+
+        @Override
+        public byte getByteProperty(String arg0) throws JMSException {
+            return 0;
+        }
+
+        @Override
+        public short getShortProperty(String arg0) throws JMSException {
+            return 0;
+        }
+
+        @Override
+        public int getIntProperty(String arg0) throws JMSException {
+            return 0;
+        }
+
+        @Override
+        public long getLongProperty(String arg0) throws JMSException {
+            return 0;
+        }
+
+        @Override
+        public float getFloatProperty(String arg0) throws JMSException {
+            return 0;
+        }
+
+        @Override
+        public double getDoubleProperty(String arg0) throws JMSException {
+            return 0;
+        }
+
+        @Override
+        public String getStringProperty(String arg0) throws JMSException {
+            return (String)props.get(arg0);
+        }
+
+        @Override
+        public Object getObjectProperty(String arg0) throws JMSException {
+            return props.get(arg0);
+        }
+
+        @Override
+        public Enumeration<?> getPropertyNames() throws JMSException {
+            return new Vector<String>(props.keySet()).elements();
+        }
+
+        @Override
+        public void setBooleanProperty(String arg0, boolean arg1) throws JMSException {
+        }
+
+        @Override
+        public void setByteProperty(String arg0, byte arg1) throws JMSException {
+        }
+
+        @Override
+        public void setShortProperty(String arg0, short arg1) throws JMSException {
+        }
+
+        @Override
+        public void setIntProperty(String arg0, int arg1) throws JMSException {
+        }
+
+        @Override
+        public void setLongProperty(String arg0, long arg1) throws JMSException {
+        }
+
+        @Override
+        public void setFloatProperty(String arg0, float arg1) throws JMSException {
+        }
+
+        @Override
+        public void setDoubleProperty(String arg0, double arg1) throws JMSException {
+        }
+
+        @Override
+        public void setStringProperty(String arg0, String arg1) throws JMSException {
+            props.put(arg0, arg1);
+        }
+
+        @Override
+        public void setObjectProperty(String arg0, Object arg1) throws JMSException {
+            props.put(arg0, arg1);
+        }
+
+        @Override
+        public void acknowledge() throws JMSException {
+        }
+
+        @Override
+        public void clearBody() throws JMSException {
+        }
+
+        @Override
+        public void setText(String arg0) throws JMSException {
+            text = arg0;
+        }
+
+        @Override
+        public String getText() throws JMSException {
+            return text;
+        }
+    }
+
+    // TODO - implement proper handling of foreign JMS Message and Destination types.
+    @Ignore("ActiveMQ is dropping messages as expired with current proton lib")
+    @Test
+    public void testForeignMessage() throws Exception {
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Destination destination = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(destination);
+        MessageProducer producer = session.createProducer(destination);
+
+        {
+            ForeignMessage message = new ForeignMessage();
+            message.text = "Hello";
+            message.setStringProperty("test", "value");
+            long timeToLive = 10000L;
+            long start = System.currentTimeMillis();
+            producer.send(message, Session.AUTO_ACKNOWLEDGE, 7, timeToLive);
+            long end = System.currentTimeMillis();
+
+            // validate jms spec 1.1 section 3.4.11 table 3.1
+            // JMSDestination, JMSDeliveryMode,  JMSExpiration, JMSPriority, JMSMessageID, and JMSTimestamp
+            // must be set by sending a message.
+
+            assertNotNull(message.getJMSDestination());
+            assertEquals(Session.AUTO_ACKNOWLEDGE, message.getJMSDeliveryMode());
+            assertTrue(start  + timeToLive <= message.getJMSExpiration());
+            assertTrue(end + timeToLive >= message.getJMSExpiration());
+            assertEquals(7, message.getJMSPriority());
+            assertNotNull(message.getJMSMessageID());
+            assertTrue(start <= message.getJMSTimestamp());
+            assertTrue(end >= message.getJMSTimestamp());
+        }
+        {
+            TextMessage message = (TextMessage)consumer.receive(10000);
+            assertNotNull(message);
+            assertEquals("Hello", message.getText());
+            assertEquals("value", message.getStringProperty("test"));
+        }
+
+        assertNull(consumer.receiveNoWait());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsQueueConnectionTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsQueueConnectionTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsQueueConnectionTest.java
new file mode 100644
index 0000000..36253c6
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsQueueConnectionTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
+import javax.jms.QueueConnection;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test basic QueueConnection creation etc.
+ */
+public class JmsQueueConnectionTest extends AmqpTestSupport {
+
+    @Test
+    public void testCreateQueueConnection() throws JMSException {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        QueueConnection connection = factory.createQueueConnection();
+        assertNotNull(connection);
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionAsSystemAdmin() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        factory.setUsername("system");
+        factory.setPassword("manager");
+        QueueConnection connection = factory.createQueueConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected = JMSSecurityException.class)
+    public void testCreateConnectionAsUnknwonUser() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        factory.setUsername("unknown");
+        factory.setPassword("unknown");
+        QueueConnection connection = factory.createQueueConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionCallSystemAdmin() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        QueueConnection connection = factory.createQueueConnection("system", "manager");
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected = JMSSecurityException.class)
+    public void testCreateConnectionCallUnknwonUser() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        QueueConnection connection = factory.createQueueConnection("unknown", "unknown");
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSSLConnectionTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSSLConnectionTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSSLConnectionTest.java
new file mode 100644
index 0000000..0e61d39
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSSLConnectionTest.java
@@ -0,0 +1,92 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.net.URI;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test that we can connect to a broker over SSL.
+ */
+public class JmsSSLConnectionTest {
+
+    private BrokerService brokerService;
+
+    public static final String PASSWORD = "password";
+    public static final String KEYSTORE = "src/test/resources/keystore";
+    public static final String KEYSTORE_TYPE = "jks";
+
+    private URI connectionURI;
+
+    @Before
+    public void setUp() throws Exception {
+        System.setProperty("javax.net.ssl.trustStore", KEYSTORE);
+        System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD);
+        System.setProperty("javax.net.ssl.trustStoreType", KEYSTORE_TYPE);
+        System.setProperty("javax.net.ssl.keyStore", KEYSTORE);
+        System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD);
+        System.setProperty("javax.net.ssl.keyStoreType", KEYSTORE_TYPE);
+
+        brokerService = new BrokerService();
+        brokerService.setPersistent(false);
+        brokerService.setAdvisorySupport(false);
+        brokerService.setDeleteAllMessagesOnStartup(true);
+        brokerService.setUseJmx(true);
+
+        TransportConnector connector = brokerService.addConnector("amqp+ssl://localhost:0");
+        brokerService.start();
+        brokerService.waitUntilStarted();
+
+        connectionURI = connector.getPublishableConnectURI();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        brokerService.stop();
+        brokerService.waitUntilStopped();
+    }
+
+    public String getConnectionURI() throws Exception {
+        return "amqps://" + connectionURI.getHost() + ":" + connectionURI.getPort();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnection() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionAndStart() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getConnectionURI());
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionClosedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionClosedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionClosedTest.java
new file mode 100644
index 0000000..efb3df3
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionClosedTest.java
@@ -0,0 +1,243 @@
+/**
+ * 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.jms;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Validates all Session contracts following a close() call.
+ */
+public class JmsSessionClosedTest extends AmqpTestSupport {
+
+    protected Connection connection;
+
+    protected Session createSession() throws Exception {
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        session.close();
+        return session;
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        connection.close();
+        super.tearDown();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateMessageFails() throws Exception {
+        Session session = createSession();
+        session.createMessage();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateTextMessageFails() throws Exception {
+        Session session = createSession();
+        session.createTextMessage();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateTextMessageWithTextFails() throws Exception {
+        Session session = createSession();
+        session.createTextMessage("TEST");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateMapMessageFails() throws Exception {
+        Session session = createSession();
+        session.createMapMessage();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateStreamMessageFails() throws Exception {
+        Session session = createSession();
+        session.createStreamMessage();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateBytesMessageFails() throws Exception {
+        Session session = createSession();
+        session.createBytesMessage();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateObjectMessageFails() throws Exception {
+        Session session = createSession();
+        session.createObjectMessage();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateObjectMessageWithObjectFails() throws Exception {
+        Session session = createSession();
+        session.createObjectMessage("TEST");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetTransactedFails() throws Exception {
+        Session session = createSession();
+        session.getTransacted();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetAcknowledgeModeFails() throws Exception {
+        Session session = createSession();
+        session.getAcknowledgeMode();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCommitFails() throws Exception {
+        Session session = createSession();
+        session.commit();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testRollbackFails() throws Exception {
+        Session session = createSession();
+        session.rollback();
+    }
+
+    @Test(timeout=30000)
+    public void testCloseDoesNotFail() throws Exception {
+        Session session = createSession();
+        session.close();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testRecoverFails() throws Exception {
+        Session session = createSession();
+        session.recover();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetMessageListenerFails() throws Exception {
+        Session session = createSession();
+        session.getMessageListener();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetMessageListenerFails() throws Exception {
+        Session session = createSession();
+        MessageListener listener = new MessageListener() {
+            @Override
+            public void onMessage(Message message) {
+            }
+        };
+        session.setMessageListener(listener);
+    }
+
+    @Test(timeout=30000, expected=RuntimeException.class)
+    public void testRunFails() throws Exception {
+        Session session = createSession();
+        session.run();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateProducerFails() throws Exception {
+        Session session = createSession();
+        Destination destination = session.createQueue("test");
+        session.createProducer(destination);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateConsumerDestinatioFails() throws Exception {
+        Session session = createSession();
+        Destination destination = session.createQueue("test");
+        session.createConsumer(destination);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateConsumerDestinatioSelectorFails() throws Exception {
+        Session session = createSession();
+        Destination destination = session.createQueue("test");
+        session.createConsumer(destination, "a = b");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateConsumerDestinatioSelectorBooleanFails() throws Exception {
+        Session session = createSession();
+        Destination destination = session.createQueue("test");
+        session.createConsumer(destination, "a = b", true);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateQueueFails() throws Exception {
+        Session session = createSession();
+        session.createQueue("TEST");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateTopicFails() throws Exception {
+        Session session = createSession();
+        session.createTopic("TEST");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateTemporaryQueueFails() throws Exception {
+        Session session = createSession();
+        session.createTemporaryQueue();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateTemporaryTopicFails() throws Exception {
+        Session session = createSession();
+        session.createTemporaryQueue();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateDurableSubscriberFails() throws Exception {
+        Session session = createSession();
+        Topic destination = session.createTopic("TEST");
+        session.createDurableSubscriber(destination, "test");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateDurableSubscriberSelectorBooleanFails() throws Exception {
+        Session session = createSession();
+        Topic destination = session.createTopic("TEST");
+        session.createDurableSubscriber(destination, "test", "a = b", false);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateQueueBrowserFails() throws Exception {
+        Session session = createSession();
+        Queue destination = session.createQueue("test");
+        session.createBrowser(destination);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testCreateQueueBrowserWithSelectorFails() throws Exception {
+        Session session = createSession();
+        Queue destination = session.createQueue("test");
+        session.createBrowser(destination, "a = b");
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testUnsubscribeFails() throws Exception {
+        Session session = createSession();
+        session.unsubscribe("test");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionFailedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionFailedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionFailedTest.java
new file mode 100644
index 0000000..5e6846c
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionFailedTest.java
@@ -0,0 +1,62 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.Wait;
+
+
+/**
+ * Tests the Session method contracts when the underlying connection is lost.
+ */
+public class JmsSessionFailedTest extends JmsSessionClosedTest {
+
+    @Override
+    protected Session createSession() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        connection.setExceptionListener(new ExceptionListener() {
+
+            @Override
+            public void onException(JMSException exception) {
+                latch.countDown();
+            }
+        });
+        connection.start();
+        stopPrimaryBroker();
+        assertTrue(latch.await(20, TimeUnit.SECONDS));
+        final JmsConnection jmsConnection = (JmsConnection) connection;
+        assertTrue(Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return !jmsConnection.isConnected();
+            }
+        }));
+        return session;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionTest.java
new file mode 100644
index 0000000..6c3ca35
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsSessionTest.java
@@ -0,0 +1,82 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test basic Session functionality.
+ */
+public class JmsSessionTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateSession() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+
+        session.close();
+    }
+
+    @Test(timeout=30000)
+    public void testSessionCreateProducer() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+
+        Queue queue = session.createQueue("test.queue");
+        MessageProducer producer = session.createProducer(queue);
+
+        producer.close();
+        session.close();
+    }
+
+    @Test(timeout=30000)
+    public void testSessionCreateConsumer() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+
+        Queue queue = session.createQueue("test.queue");
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        consumer.close();
+        session.close();
+    }
+
+    @Test(timeout=30000)
+    public void testSessionDoubleCloseWithoutException() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        session.close();
+        session.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsTopicConnectionTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsTopicConnectionTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsTopicConnectionTest.java
new file mode 100644
index 0000000..e423139
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/JmsTopicConnectionTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.jms;
+
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.JMSException;
+import javax.jms.JMSSecurityException;
+import javax.jms.TopicConnection;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JmsTopicConnectionTest extends AmqpTestSupport {
+
+    @Test
+    public void testCreateQueueConnection() throws JMSException {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        TopicConnection connection = factory.createTopicConnection();
+        assertNotNull(connection);
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionAsSystemAdmin() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        factory.setUsername("system");
+        factory.setPassword("manager");
+        TopicConnection connection = factory.createTopicConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000)
+    public void testCreateConnectionCallSystemAdmin() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        TopicConnection connection = factory.createTopicConnection("system", "manager");
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected = JMSSecurityException.class)
+    public void testCreateConnectionAsUnknwonUser() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        factory.setUsername("unknown");
+        factory.setPassword("unknown");
+        TopicConnection connection = factory.createTopicConnection();
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=30000, expected = JMSSecurityException.class)
+    public void testCreateConnectionCallUnknownUser() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        TopicConnection connection = factory.createTopicConnection("unknown", "unknown");
+        assertNotNull(connection);
+        connection.start();
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ConsumeFromAMQPTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ConsumeFromAMQPTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ConsumeFromAMQPTest.java
new file mode 100644
index 0000000..90d7358
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ConsumeFromAMQPTest.java
@@ -0,0 +1,236 @@
+/**
+ * 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.jms.bench;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.broker.region.policy.PolicyEntry;
+import org.apache.activemq.broker.region.policy.PolicyMap;
+import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ */
+@Ignore
+public class ConsumeFromAMQPTest extends AmqpTestSupport {
+
+    private final int MSG_COUNT = 50 * 1000;
+    private final int NUM_RUNS = 10;
+
+    @Override
+    protected boolean isForceAsyncSends() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAlwaysSyncSend() {
+        return false;
+    }
+
+    @Override
+    protected String getAmqpTransformer() {
+        return "raw";
+    }
+
+    @Override
+    protected boolean isMessagePrioritySupported() {
+        return false;
+    }
+
+    @Override
+    protected boolean isSendAcksAsync() {
+        return true;
+    }
+
+    @Override
+    public String getAmqpConnectionURIOptions() {
+        return "provider.presettleProducers=true&provider.presettleConsumers=true";
+    }
+
+    @Test
+    public void oneConsumedForProfile() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+        producer.send(message);
+        producer.close();
+
+        QueueViewMBean queueView = getProxyToQueue(getDestinationName());
+        assertEquals("Queue should have a message", 1, queueView.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message received = consumer.receive(7000);
+        assertNotNull(received);
+        consumer.close();
+
+        assertEquals("Queue should have ano messages", 0, queueView.getQueueSize());
+    }
+
+    @Test
+    public void testConsumeRateFromQueue() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+
+        // Warm Up the broker.
+        produceMessages(queue, MSG_COUNT);
+        consumerMessages(queue, MSG_COUNT);
+        QueueViewMBean queueView = getProxyToQueue(getDestinationName());
+        queueView.purge();
+
+        List<Long> sendTimes = new ArrayList<Long>();
+        long cumulative = 0;
+
+        for (int i = 0; i < NUM_RUNS; ++i) {
+            produceMessages(queue, MSG_COUNT);
+            long result = consumerMessages(queue, MSG_COUNT);
+            sendTimes.add(result);
+            cumulative += result;
+            LOG.info("Time to send {} topic messages: {} ms", MSG_COUNT, result);
+            queueView.purge();
+        }
+
+        long smoothed = cumulative / NUM_RUNS;
+        LOG.info("Smoothed send time for {} messages: {}", MSG_COUNT, smoothed);
+    }
+
+    @Test
+    public void testConsumeRateFromQueueAsync() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+
+        // Warm Up the broker.
+        produceMessages(queue, MSG_COUNT);
+        consumerMessagesAsync(queue, MSG_COUNT);
+
+        QueueViewMBean queueView = getProxyToQueue(getDestinationName());
+
+        List<Long> sendTimes = new ArrayList<Long>();
+        long cumulative = 0;
+
+        for (int i = 0; i < NUM_RUNS; ++i) {
+            produceMessages(queue, MSG_COUNT);
+            long result = consumerMessagesAsync(queue, MSG_COUNT);
+            sendTimes.add(result);
+            cumulative += result;
+            LOG.info("Time to send {} topic messages: {} ms", MSG_COUNT, result);
+            queueView.purge();
+        }
+
+        long smoothed = cumulative / NUM_RUNS;
+        LOG.info("Smoothed send time for {} messages: {}", MSG_COUNT, smoothed);
+    }
+
+    protected long consumerMessages(Destination destination, int msgCount) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageConsumer consumer = session.createConsumer(destination);
+
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < msgCount; ++i) {
+            Message message = consumer.receive(7000);
+            assertNotNull("Failed to receive message " + i, message);
+        }
+        long result = (System.currentTimeMillis() - startTime);
+
+        consumer.close();
+        return result;
+    }
+
+    protected long consumerMessagesAsync(Destination destination, int msgCount) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageConsumer consumer = session.createConsumer(destination);
+
+        final CountDownLatch doneLatch = new CountDownLatch(MSG_COUNT);
+        long startTime = System.currentTimeMillis();
+        consumer.setMessageListener(new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+                doneLatch.countDown();
+            }
+        });
+        assertTrue(doneLatch.await(60, TimeUnit.SECONDS));
+        long result = (System.currentTimeMillis() - startTime);
+
+        consumer.close();
+        return result;
+    }
+
+    protected void produceMessages(Destination destination, int msgCount) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageProducer producer = session.createProducer(destination);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+
+        for (int i = 0; i < msgCount; ++i) {
+            producer.send(message);
+        }
+
+        producer.close();
+    }
+
+    @Override
+    protected void configureBrokerPolicies(BrokerService broker) {
+        PolicyEntry policyEntry = new PolicyEntry();
+        policyEntry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy());
+        policyEntry.setPrioritizedMessages(false);
+        policyEntry.setExpireMessagesPeriod(0);
+        policyEntry.setEnableAudit(false);
+        policyEntry.setOptimizedDispatch(false);
+        policyEntry.setQueuePrefetch(1000);
+
+        PolicyMap policyMap = new PolicyMap();
+        policyMap.setDefaultEntry(policyEntry);
+        broker.setDestinationPolicy(policyMap);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToAMQPTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToAMQPTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToAMQPTest.java
new file mode 100644
index 0000000..9077f08
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToAMQPTest.java
@@ -0,0 +1,169 @@
+/**
+ * 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.jms.bench;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.activemq.broker.region.policy.PolicyEntry;
+import org.apache.activemq.broker.region.policy.PolicyMap;
+import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Collect some basic throughput data on message producer.
+ */
+@Ignore
+public class ProduceToAMQPTest extends AmqpTestSupport {
+
+    private final int MSG_COUNT = 50 * 1000;
+    private final int NUM_RUNS = 20;
+
+    @Override
+    protected boolean isForceAsyncSends() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAlwaysSyncSend() {
+        return false;
+    }
+
+    @Override
+    protected String getAmqpTransformer() {
+        return "raw";
+    }
+
+    @Override
+    public String getAmqpConnectionURIOptions() {
+        return "provider.presettle=true";
+    }
+
+    @Test
+    public void singleSendProfile() throws Exception {
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Topic topic = session.createTopic(getDestinationName());
+        MessageProducer producer = session.createProducer(topic);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+        producer.send(message);
+        producer.close();
+    }
+
+    @Test
+    public void testProduceRateToTopic() throws Exception {
+
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Topic topic = session.createTopic(getDestinationName());
+
+        // Warm Up the broker.
+        produceMessages(topic, MSG_COUNT);
+
+        List<Long> sendTimes = new ArrayList<Long>();
+        long cumulative = 0;
+
+        for (int i = 0; i < NUM_RUNS; ++i) {
+            long result = produceMessages(topic, MSG_COUNT);
+            sendTimes.add(result);
+            cumulative += result;
+            LOG.info("Time to send {} topic messages: {} ms", MSG_COUNT, result);
+        }
+
+        long smoothed = cumulative / NUM_RUNS;
+        LOG.info("Smoothed send time for {} messages: {}", MSG_COUNT, smoothed);
+        TimeUnit.SECONDS.sleep(1);
+    }
+
+    @Test
+    public void testProduceRateToQueue() throws Exception {
+
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+
+        // Warm Up the broker.
+        produceMessages(queue, MSG_COUNT);
+
+        QueueViewMBean queueView = getProxyToQueue(getDestinationName());
+        queueView.purge();
+
+        List<Long> sendTimes = new ArrayList<Long>();
+        long cumulative = 0;
+
+        for (int i = 0; i < NUM_RUNS; ++i) {
+            long result = produceMessages(queue, MSG_COUNT);
+            sendTimes.add(result);
+            cumulative += result;
+            LOG.info("Time to send {} queue messages: {} ms", MSG_COUNT, result);
+            queueView.purge();
+        }
+
+        long smoothed = cumulative / NUM_RUNS;
+        LOG.info("Smoothed send time for {} messages: {}", MSG_COUNT, smoothed);
+        TimeUnit.SECONDS.sleep(1);
+    }
+
+    protected long produceMessages(Destination destination, int msgCount) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageProducer producer = session.createProducer(destination);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < msgCount; ++i) {
+            producer.send(message);
+        }
+        long result = (System.currentTimeMillis() - startTime);
+
+        producer.close();
+        return result;
+    }
+
+    @Override
+    protected void configureBrokerPolicies(BrokerService broker) {
+        PolicyEntry policyEntry = new PolicyEntry();
+        policyEntry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy());
+        policyEntry.setPrioritizedMessages(false);
+        policyEntry.setExpireMessagesPeriod(0);
+        policyEntry.setEnableAudit(false);
+        policyEntry.setOptimizedDispatch(true);
+        policyEntry.setQueuePrefetch(100);
+
+        PolicyMap policyMap = new PolicyMap();
+        policyMap.setDefaultEntry(policyEntry);
+        broker.setDestinationPolicy(policyMap);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToOpenWireTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToOpenWireTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToOpenWireTest.java
new file mode 100644
index 0000000..3fa8fd5
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProduceToOpenWireTest.java
@@ -0,0 +1,129 @@
+/**
+ * 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.jms.bench;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.DeliveryMode;
+import javax.jms.Destination;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Ignore
+public class ProduceToOpenWireTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(ProduceToOpenWireTest.class);
+
+    private final int MSG_COUNT = 50 * 1000;
+    private final int NUM_RUNS = 40;
+
+    @Test
+    public void singleSendProfile() throws Exception {
+        connection = createActiveMQConnection();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Topic topic = session.createTopic(getDestinationName());
+        MessageProducer producer = session.createProducer(topic);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+        producer.send(message);
+    }
+
+    @Test
+    public void testProduceRateToTopic() throws Exception {
+
+        connection = createActiveMQConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Topic topic = session.createTopic(getDestinationName());
+
+        // Warm Up the broker.
+        produceMessages(topic, MSG_COUNT);
+
+        List<Long> sendTimes = new ArrayList<Long>();
+        long cumulative = 0;
+
+        for (int i = 0; i < NUM_RUNS; ++i) {
+            long result = produceMessages(topic, MSG_COUNT);
+            sendTimes.add(result);
+            cumulative += result;
+            LOG.info("Time to send {} topic messages: {} ms", MSG_COUNT, result);
+        }
+
+        long smoothed = cumulative / NUM_RUNS;
+        LOG.info("Smoothed send time for {} messages: {}", MSG_COUNT, smoothed);
+    }
+
+    @Test
+    public void testProduceRateToQueue() throws Exception {
+
+        connection = createActiveMQConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+
+        // Warm Up the broker.
+        produceMessages(queue, MSG_COUNT);
+
+        QueueViewMBean queueView = getProxyToQueue(getDestinationName());
+        queueView.purge();
+
+        List<Long> sendTimes = new ArrayList<Long>();
+        long cumulative = 0;
+
+        for (int i = 0; i < NUM_RUNS; ++i) {
+            long result = produceMessages(queue, MSG_COUNT);
+            sendTimes.add(result);
+            cumulative += result;
+            LOG.info("Time to send {} queue messages: {} ms", MSG_COUNT, result);
+            queueView.purge();
+        }
+
+        long smoothed = cumulative / NUM_RUNS;
+        LOG.info("Smoothed send time for {} messages: {}", MSG_COUNT, smoothed);
+    }
+
+    protected long produceMessages(Destination destination, int msgCount) throws Exception {
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        MessageProducer producer = session.createProducer(destination);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+
+        TextMessage message = session.createTextMessage();
+        message.setText("hello");
+
+        long startTime = System.currentTimeMillis();
+        for (int i = 0; i < msgCount; ++i) {
+            producer.send(message);
+        }
+
+        long result = (System.currentTimeMillis() - startTime);
+
+        producer.close();
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProducerAndConsumerBench.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProducerAndConsumerBench.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProducerAndConsumerBench.java
new file mode 100644
index 0000000..0dacc84
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/bench/ProducerAndConsumerBench.java
@@ -0,0 +1,202 @@
+/**
+ * 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.jms.bench;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Vector;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.jms.BytesMessage;
+import javax.jms.ConnectionFactory;
+import javax.jms.DeliveryMode;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.ActiveMQSession;
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.region.policy.PolicyEntry;
+import org.apache.activemq.broker.region.policy.PolicyMap;
+import org.apache.activemq.broker.region.policy.VMPendingQueueMessageStoragePolicy;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+@Ignore
+public class ProducerAndConsumerBench extends AmqpTestSupport  {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ProducerAndConsumerBench.class);
+
+    public static final int payload = 64 * 1024;
+    public static final int ioBuffer = 2 * payload;
+    public static final int socketBuffer = 64 * payload;
+
+    private final String payloadString = new String(new byte[payload]);
+    private final int parallelProducer = 1;
+    private final int parallelConsumer = 1;
+    private final Vector<Throwable> exceptions = new Vector<Throwable>();
+    private ConnectionFactory factory;
+
+    private final long NUM_SENDS = 30000;
+
+    @Test
+    public void testProduceConsume() throws Exception {
+        this.factory = createAmqpConnectionFactory();
+
+        final AtomicLong sharedSendCount = new AtomicLong(NUM_SENDS);
+        final AtomicLong sharedReceiveCount = new AtomicLong(NUM_SENDS);
+
+        Thread.sleep(2000);
+
+        long start = System.currentTimeMillis();
+        ExecutorService executorService = Executors.newFixedThreadPool(parallelConsumer + parallelProducer);
+
+        for (int i = 0; i < parallelConsumer; i++) {
+            executorService.execute(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        consumeMessages(sharedReceiveCount);
+                    } catch (Throwable e) {
+                        exceptions.add(e);
+                    }
+                }
+            });
+        }
+        for (int i = 0; i < parallelProducer; i++) {
+            executorService.execute(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        publishMessages(sharedSendCount);
+                    } catch (Throwable e) {
+                        exceptions.add(e);
+                    }
+                }
+            });
+        }
+
+        executorService.shutdown();
+        executorService.awaitTermination(30, TimeUnit.MINUTES);
+        assertTrue("Producers done in time", executorService.isTerminated());
+        assertTrue("No exceptions: " + exceptions, exceptions.isEmpty());
+
+        double duration = System.currentTimeMillis() - start;
+        LOG.info("Duration:            " + duration + "ms");
+        LOG.info("Rate:                " + (NUM_SENDS * 1000 / duration) + "m/s");
+    }
+
+    private void consumeMessages(AtomicLong count) throws Exception {
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        connection.start();
+        Session session = connection.createSession(false, ActiveMQSession.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        long v;
+        while ((v = count.decrementAndGet()) > 0) {
+            assertNotNull("got message " + v, consumer.receive(15000));
+        }
+        consumer.close();
+    }
+
+    private void publishMessages(AtomicLong count) throws Exception {
+        JmsConnection connection = (JmsConnection) factory.createConnection();
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(getDestinationName());
+
+        MessageProducer producer = session.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
+        Message message = session.createBytesMessage();
+        ((BytesMessage) message).writeBytes(payloadString.getBytes());
+
+        while (count.getAndDecrement() > 0) {
+            producer.send(message);
+        }
+        producer.close();
+        connection.close();
+    }
+
+    @Override
+    protected void configureBrokerPolicies(BrokerService broker) {
+        PolicyEntry policyEntry = new PolicyEntry();
+        policyEntry.setPendingQueuePolicy(new VMPendingQueueMessageStoragePolicy());
+        policyEntry.setPrioritizedMessages(false);
+        policyEntry.setExpireMessagesPeriod(0);
+        policyEntry.setEnableAudit(false);
+        policyEntry.setOptimizedDispatch(true);
+        policyEntry.setQueuePrefetch(1); // ensure no contention on add with
+                                         // matched producer/consumer
+
+        PolicyMap policyMap = new PolicyMap();
+        policyMap.setDefaultEntry(policyEntry);
+        broker.setDestinationPolicy(policyMap);
+    }
+
+    @Override
+    protected boolean isForceAsyncSends() {
+        return true;
+    }
+
+    @Override
+    protected boolean isAlwaysSyncSend() {
+        return false;
+    }
+
+    @Override
+    protected String getAmqpTransformer() {
+        return "raw";
+    }
+
+    @Override
+    protected boolean isMessagePrioritySupported() {
+        return false;
+    }
+
+    @Override
+    protected boolean isSendAcksAsync() {
+        return true;
+    }
+
+    @Override
+    public String getAmqpConnectionURIOptions() {
+        return "provider.presettleProducers=true&provider.presettleConsumers=true";
+    }
+
+    @Override
+    protected int getSocketBufferSize() {
+        return socketBuffer;
+    }
+
+    @Override
+    protected int getIOBufferSize() {
+        return ioBuffer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsAutoAckTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsAutoAckTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsAutoAckTest.java
new file mode 100644
index 0000000..db2a104
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/consumer/JmsAutoAckTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.jms.consumer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class JmsAutoAckTest extends AmqpTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(JmsAutoAckTest.class);
+
+    @Test(timeout = 60000)
+    public void testAckedMessageAreConsumed() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        sendToAmqQueue(1);
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        assertNotNull("Failed to receive any message.", consumer.receive(2000));
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+
+    @Test(timeout = 60000)
+    public void testAckedMessageAreConsumedAsync() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        sendToAmqQueue(1);
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        consumer.setMessageListener(new MessageListener() {
+
+            @Override
+            public void onMessage(Message message) {
+                LOG.debug("Received async message: {}", message);
+            }
+        });
+
+        assertTrue("Queued message not consumed.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == 0;
+            }
+        }));
+    }
+}


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


[19/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
new file mode 100644
index 0000000..4253434
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConnection.java
@@ -0,0 +1,285 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.JMSSecurityException;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.provider.amqp.message.AmqpJmsMessageFactory;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Sasl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AmqpConnection extends AbstractAmqpResource<JmsConnectionInfo, Connection> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpConnection.class);
+
+    private final AmqpJmsMessageFactory amqpMessageFactory;
+
+    private final URI remoteURI;
+    private final Map<JmsSessionId, AmqpSession> sessions = new HashMap<JmsSessionId, AmqpSession>();
+    private final Map<JmsDestination, AmqpTemporaryDestination> tempDests = new HashMap<JmsDestination, AmqpTemporaryDestination>();
+    private final AmqpProvider provider;
+    private boolean connected;
+    private AmqpSaslAuthenticator authenticator;
+    private final AmqpSession connectionSession;
+
+    private String queuePrefix;
+    private String topicPrefix;
+    private String tempQueuePrefix;
+    private String tempTopicPrefix;
+
+    public AmqpConnection(AmqpProvider provider, Connection protonConnection, Sasl sasl, JmsConnectionInfo info) {
+        super(info, protonConnection);
+
+        this.provider = provider;
+        this.remoteURI = provider.getRemoteURI();
+        this.amqpMessageFactory = new AmqpJmsMessageFactory(this);
+
+        if (sasl != null) {
+            this.authenticator = new AmqpSaslAuthenticator(sasl, info);
+        }
+
+        this.info.getConnectionId().setProviderHint(this);
+
+        this.queuePrefix = info.getQueuePrefix();
+        this.topicPrefix = info.getTopicPrefix();
+        this.tempQueuePrefix = info.getTempQueuePrefix();
+        this.tempTopicPrefix = info.getTempTopicPrefix();
+
+        // Create a Session for this connection that is used for Temporary Destinations
+        // and perhaps later on management and advisory monitoring.
+        JmsSessionInfo sessionInfo = new JmsSessionInfo(this.info, -1);
+        sessionInfo.setAcknowledgementMode(Session.AUTO_ACKNOWLEDGE);
+
+        this.connectionSession = new AmqpSession(this, sessionInfo);
+    }
+
+    @Override
+    protected void doOpen() {
+        this.endpoint.setContainer(info.getClientId());
+        this.endpoint.setHostname(remoteURI.getHost());
+    }
+
+    @Override
+    protected void doClose() {
+    }
+
+    public AmqpSession createSession(JmsSessionInfo sessionInfo) {
+        AmqpSession session = new AmqpSession(this, sessionInfo);
+        return session;
+    }
+
+    public AmqpTemporaryDestination createTemporaryDestination(JmsDestination destination) {
+        AmqpTemporaryDestination temporary = new AmqpTemporaryDestination(connectionSession, destination);
+        return temporary;
+    }
+
+    /**
+     * Called on receiving an event from Proton indicating a state change on the remote
+     * side of the Connection.
+     */
+    @Override
+    public void processStateChange() {
+
+        if (!connected && isOpen()) {
+            connected = true;
+            connectionSession.open(new AsyncResult() {
+
+                @Override
+                public boolean isComplete() {
+                    return connected;
+                }
+
+                @Override
+                public void onSuccess() {
+                    LOG.debug("AMQP Connection Session opened.");
+                    opened();
+                }
+
+                @Override
+                public void onFailure(Throwable result) {
+                    LOG.debug("AMQP Connection Session failed to open.");
+                    failed(IOExceptionSupport.create(result));
+                }
+            });
+        }
+
+        EndpointState localState = endpoint.getLocalState();
+        EndpointState remoteState = endpoint.getRemoteState();
+
+        // We are still active (connected or not) and something on the remote end has
+        // closed us, signal an error if one was sent.
+        if (localState == EndpointState.ACTIVE && remoteState != EndpointState.ACTIVE) {
+            if (endpoint.getRemoteCondition().getCondition() != null) {
+                LOG.info("Error condition detected on Connection open {}.", endpoint.getRemoteCondition().getCondition());
+                Exception remoteError = getRemoteError();
+                if (isAwaitingOpen()) {
+                    openRequest.onFailure(remoteError);
+                } else {
+                    provider.fireProviderException(remoteError);
+                }
+            }
+        }
+
+        // Transition cleanly to closed state.
+        if (localState == EndpointState.CLOSED && remoteState == EndpointState.CLOSED) {
+            LOG.debug("{} has been closed successfully.", this);
+            closed();
+        }
+    }
+
+    public void processSaslAuthentication() {
+        if (connected || authenticator == null) {
+            return;
+        }
+
+        try {
+            if (authenticator.authenticate()) {
+                authenticator = null;
+            }
+        } catch (JMSSecurityException ex) {
+            failed(ex);
+        }
+    }
+
+    void addTemporaryDestination(AmqpTemporaryDestination destination) {
+        tempDests.put(destination.getJmsDestination(), destination);
+    }
+
+    void removeTemporaryDestination(AmqpTemporaryDestination destination) {
+        tempDests.remove(destination.getJmsDestination());
+    }
+
+    void addSession(AmqpSession session) {
+        this.sessions.put(session.getSessionId(), session);
+    }
+
+    void removeSession(AmqpSession session) {
+        this.sessions.remove(session.getSessionId());
+    }
+
+    public JmsConnectionInfo getConnectionInfo() {
+        return this.info;
+    }
+
+    public Connection getProtonConnection() {
+        return this.endpoint;
+    }
+
+    public URI getRemoteURI() {
+        return this.remoteURI;
+    }
+
+    public String getUsername() {
+        return this.info.getUsername();
+    }
+
+    public String getPassword() {
+        return this.info.getPassword();
+    }
+
+    public AmqpProvider getProvider() {
+        return this.provider;
+    }
+
+    public String getQueuePrefix() {
+        return queuePrefix;
+    }
+
+    public void setQueuePrefix(String queuePrefix) {
+        this.queuePrefix = queuePrefix;
+    }
+
+    public String getTopicPrefix() {
+        return topicPrefix;
+    }
+
+    public void setTopicPrefix(String topicPrefix) {
+        this.topicPrefix = topicPrefix;
+    }
+
+    public String getTempQueuePrefix() {
+        return tempQueuePrefix;
+    }
+
+    public void setTempQueuePrefix(String tempQueuePrefix) {
+        this.tempQueuePrefix = tempQueuePrefix;
+    }
+
+    public String getTempTopicPrefix() {
+        return tempTopicPrefix;
+    }
+
+    public void setTempTopicPrefix(String tempTopicPrefix) {
+        this.tempTopicPrefix = tempTopicPrefix;
+    }
+
+    /**
+     * Retrieve the indicated Session instance from the list of active sessions.
+     *
+     * @param sessionId
+     *        The JmsSessionId that's associated with the target session.
+     *
+     * @return the AmqpSession associated with the given id.
+     */
+    public AmqpSession getSession(JmsSessionId sessionId) {
+        if (sessionId.getProviderHint() instanceof AmqpSession) {
+            return (AmqpSession) sessionId.getProviderHint();
+        }
+        return this.sessions.get(sessionId);
+    }
+
+    /**
+     * @return true if the provider has been configured for presettle operations.
+     */
+    public boolean isPresettleConsumers() {
+        return provider.isPresettleConsumers();
+    }
+
+    /**
+     * @return true if the provider has been configured for presettle operations.
+     */
+    public boolean isPresettleProducers() {
+        return provider.isPresettleProducers();
+    }
+
+    /**
+     * @return the AMQP based JmsMessageFactory for this Connection.
+     */
+    public AmqpJmsMessageFactory getAmqpMessageFactory() {
+        return this.amqpMessageFactory;
+    }
+
+    @Override
+    public String toString() {
+        return "AmqpConnection { " + getConnectionInfo().getConnectionId() + " }";
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
new file mode 100644
index 0000000..3ecb58e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpConsumer.java
@@ -0,0 +1,461 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.meta.JmsMessageId;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.provider.ProviderListener;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.messaging.Accepted;
+import org.apache.qpid.proton.amqp.messaging.Modified;
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.apache.qpid.proton.amqp.messaging.Target;
+import org.apache.qpid.proton.amqp.messaging.TerminusDurability;
+import org.apache.qpid.proton.amqp.messaging.TerminusExpiryPolicy;
+import org.apache.qpid.proton.amqp.transaction.TransactionalState;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.jms.EncodedMessage;
+import org.apache.qpid.proton.jms.InboundTransformer;
+import org.apache.qpid.proton.jms.JMSMappingInboundTransformer;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtbuf.ByteArrayOutputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AMQP Consumer object that is used to manage JMS MessageConsumer semantics.
+ */
+public class AmqpConsumer extends AbstractAmqpResource<JmsConsumerInfo, Receiver> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpConsumer.class);
+
+    protected static final Symbol COPY = Symbol.getSymbol("copy");
+    protected static final Symbol JMS_NO_LOCAL_SYMBOL = Symbol.valueOf("no-local");
+    protected static final Symbol JMS_SELECTOR_SYMBOL = Symbol.valueOf("jms-selector");
+
+    protected final AmqpSession session;
+    protected final InboundTransformer inboundTransformer =
+        new JMSMappingInboundTransformer(AmqpJMSVendor.INSTANCE);;
+    protected final Map<JmsMessageId, Delivery> delivered = new LinkedHashMap<JmsMessageId, Delivery>();
+    protected boolean presettle;
+
+    private final ByteArrayOutputStream streamBuffer = new ByteArrayOutputStream();
+    private final byte incomingBuffer[] = new byte[1024 * 64];
+
+    public AmqpConsumer(AmqpSession session, JmsConsumerInfo info) {
+        super(info);
+        this.session = session;
+
+        // Add a shortcut back to this Consumer for quicker lookups
+        this.info.getConsumerId().setProviderHint(this);
+    }
+
+    /**
+     * Starts the consumer by setting the link credit to the given prefetch value.
+     */
+    public void start(AsyncResult request) {
+        this.endpoint.flow(info.getPrefetchSize());
+        request.onSuccess();
+    }
+
+    @Override
+    protected void doOpen() {
+        JmsDestination destination  = info.getDestination();
+        String subscription = session.getQualifiedName(destination);
+
+        Source source = new Source();
+        source.setAddress(subscription);
+        Target target = new Target();
+
+        configureSource(source);
+
+        String receiverName = getConsumerId() + ":" + subscription;
+        if (info.getSubscriptionName() != null && !info.getSubscriptionName().isEmpty()) {
+            // In the case of Durable Topic Subscriptions the client must use the same
+            // receiver name which is derived from the subscription name property.
+            receiverName = info.getSubscriptionName();
+        }
+
+        endpoint = session.getProtonSession().receiver(receiverName);
+        endpoint.setSource(source);
+        endpoint.setTarget(target);
+        if (isPresettle()) {
+            endpoint.setSenderSettleMode(SenderSettleMode.SETTLED);
+        } else {
+            endpoint.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        }
+        endpoint.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+    }
+
+    @Override
+    public void opened() {
+        this.session.addResource(this);
+        super.opened();
+    }
+
+    @Override
+    public void closed() {
+        this.session.removeResource(this);
+        super.closed();
+    }
+
+    protected void configureSource(Source source) {
+        Map<Symbol, DescribedType> filters = new HashMap<Symbol, DescribedType>();
+
+        if (info.getSubscriptionName() != null && !info.getSubscriptionName().isEmpty()) {
+            source.setExpiryPolicy(TerminusExpiryPolicy.NEVER);
+            source.setDurable(TerminusDurability.UNSETTLED_STATE);
+            source.setDistributionMode(COPY);
+        } else {
+            source.setDurable(TerminusDurability.NONE);
+            source.setExpiryPolicy(TerminusExpiryPolicy.LINK_DETACH);
+        }
+
+        if (info.isNoLocal()) {
+            filters.put(JMS_NO_LOCAL_SYMBOL, AmqpJmsNoLocalType.NO_LOCAL);
+        }
+
+        if (info.getSelector() != null && !info.getSelector().trim().equals("")) {
+            filters.put(JMS_SELECTOR_SYMBOL, new AmqpJmsSelectorType(info.getSelector()));
+        }
+
+        if (!filters.isEmpty()) {
+            source.setFilter(filters);
+        }
+    }
+
+    /**
+     * Called to acknowledge all messages that have been marked as delivered but
+     * have not yet been marked consumed.  Usually this is called as part of an
+     * client acknowledge session operation.
+     *
+     * Only messages that have already been acknowledged as delivered by the JMS
+     * framework will be in the delivered Map.  This means that the link credit
+     * would already have been given for these so we just need to settle them.
+     */
+    public void acknowledge() {
+        LOG.trace("Session Acknowledge for consumer: {}", info.getConsumerId());
+        for (Delivery delivery : delivered.values()) {
+            delivery.disposition(Accepted.getInstance());
+            delivery.settle();
+        }
+        delivered.clear();
+    }
+
+    /**
+     * Called to acknowledge a given delivery.  Depending on the Ack Mode that
+     * the consumer was created with this method can acknowledge more than just
+     * the target delivery.
+     *
+     * @param envelope
+     *        the delivery that is to be acknowledged.
+     * @param ackType
+     *        the type of acknowledgment to perform.
+     *
+     * @throws JMSException if an error occurs accessing the Message properties.
+     */
+    public void acknowledge(JmsInboundMessageDispatch envelope, ACK_TYPE ackType) throws JMSException {
+        JmsMessageId messageId = envelope.getMessage().getFacade().getMessageId();
+        Delivery delivery = null;
+
+        if (messageId.getProviderHint() instanceof Delivery) {
+            delivery = (Delivery) messageId.getProviderHint();
+        } else {
+            delivery = delivered.get(messageId);
+            if (delivery == null) {
+                LOG.warn("Received Ack for unknown message: {}", messageId);
+                return;
+            }
+        }
+
+        if (ackType.equals(ACK_TYPE.DELIVERED)) {
+            LOG.debug("Delivered Ack of message: {}", messageId);
+            if (session.isTransacted()) {
+                Binary txnId = session.getTransactionContext().getAmqpTransactionId();
+                if (txnId != null) {
+                    TransactionalState txState = new TransactionalState();
+                    txState.setOutcome(Accepted.getInstance());
+                    txState.setTxnId(txnId);
+                    delivery.disposition(txState);
+                    session.getTransactionContext().registerTxConsumer(this);
+                }
+            }
+            if (!isPresettle()) {
+                delivered.put(messageId, delivery);
+            }
+            sendFlowIfNeeded();
+        } else if (ackType.equals(ACK_TYPE.CONSUMED)) {
+            // A Consumer may not always send a delivered ACK so we need to check to
+            // ensure we don't add to much credit to the link.
+            if (isPresettle() || delivered.remove(messageId) == null) {
+                sendFlowIfNeeded();
+            }
+            LOG.debug("Consumed Ack of message: {}", messageId);
+            if (!delivery.isSettled()) {
+                delivery.disposition(Accepted.getInstance());
+                delivery.settle();
+            }
+        } else if (ackType.equals(ACK_TYPE.REDELIVERED)) {
+            Modified disposition = new Modified();
+            disposition.setUndeliverableHere(false);
+            disposition.setDeliveryFailed(true);
+            delivery.disposition(disposition);
+            delivery.settle();
+        } else if (ackType.equals(ACK_TYPE.POISONED)) {
+            deliveryFailed(delivery, false);
+        } else {
+            LOG.warn("Unsupporeted Ack Type for message: {}", messageId);
+        }
+    }
+
+    /**
+     * We only send more credits as the credit window dwindles to a certain point and
+     * then we open the window back up to full prefetch size.
+     */
+    private void sendFlowIfNeeded() {
+        if (info.getPrefetchSize() == 0) {
+            return;
+        }
+
+        int currentCredit = endpoint.getCredit();
+        if (currentCredit <= info.getPrefetchSize() * 0.2) {
+            endpoint.flow(info.getPrefetchSize() - currentCredit);
+        }
+    }
+
+    /**
+     * Recovers all previously delivered but not acknowledged messages.
+     *
+     * @throws Exception if an error occurs while performing the recover.
+     */
+    public void recover() throws Exception {
+        LOG.debug("Session Recover for consumer: {}", info.getConsumerId());
+        for (Delivery delivery : delivered.values()) {
+            // TODO - increment redelivery counter and apply connection redelivery policy
+            //        to those messages that are past max redlivery.
+            JmsInboundMessageDispatch envelope = (JmsInboundMessageDispatch) delivery.getContext();
+            envelope.onMessageRedelivered();
+            deliver(envelope);
+        }
+        delivered.clear();
+    }
+
+    /**
+     * For a consumer whose prefetch value is set to zero this method will attempt to solicite
+     * a new message dispatch from the broker.
+     *
+     * @param timeout
+     */
+    public void pull(long timeout) {
+        if (info.getPrefetchSize() == 0 && endpoint.getCredit() == 0) {
+            // expand the credit window by one.
+            endpoint.flow(1);
+        }
+    }
+
+    @Override
+    public void processDeliveryUpdates() throws IOException {
+        Delivery incoming = null;
+        do {
+            incoming = endpoint.current();
+            if (incoming != null && incoming.isReadable() && !incoming.isPartial()) {
+                LOG.trace("{} has incoming Message(s).", this);
+                try {
+                    processDelivery(incoming);
+                } catch (Exception e) {
+                    throw IOExceptionSupport.create(e);
+                }
+                endpoint.advance();
+            } else {
+                LOG.trace("{} has a partial incoming Message(s), deferring.", this);
+                incoming = null;
+            }
+        } while (incoming != null);
+    }
+
+    private void processDelivery(Delivery incoming) throws Exception {
+        EncodedMessage encoded = readIncomingMessage(incoming);
+        JmsMessage message = null;
+        try {
+            message = (JmsMessage) inboundTransformer.transform(encoded);
+        } catch (Exception e) {
+            LOG.warn("Error on transform: {}", e.getMessage());
+            // TODO - We could signal provider error but not sure we want to fail
+            //        the connection just because we can't convert the message.
+            //        In the future once the JMS mapping is complete we should be
+            //        able to convert everything to some message even if its just
+            //        a bytes messages as a fall back.
+            deliveryFailed(incoming, true);
+            return;
+        }
+
+        try {
+            message.setJMSDestination(info.getDestination());
+        } catch (JMSException e) {
+            LOG.warn("Error on transform: {}", e.getMessage());
+            // TODO - We could signal provider error but not sure we want to fail
+            //        the connection just because we can't convert the destination.
+            deliveryFailed(incoming, true);
+            return;
+        }
+
+        // Store link to delivery in the hint for use in acknowledge requests.
+        message.getFacade().getMessageId().setProviderHint(incoming);
+
+        // We need to signal to the create message that it's being dispatched and for now
+        // the transformer creates the message in write mode, onSend will reset it to read
+        // mode and the consumer will see it as a normal received message.
+        message.onSend();
+
+        JmsInboundMessageDispatch envelope = new JmsInboundMessageDispatch();
+        envelope.setMessage(message);
+        envelope.setConsumerId(info.getConsumerId());
+        envelope.setProviderHint(incoming);
+
+        // Store reference to envelope in delivery context for recovery
+        incoming.setContext(envelope);
+
+        deliver(envelope);
+    }
+
+    @Override
+    protected void doClose() {
+    }
+
+    public AmqpSession getSession() {
+        return this.session;
+    }
+
+    public JmsConsumerId getConsumerId() {
+        return this.info.getConsumerId();
+    }
+
+    public Receiver getProtonReceiver() {
+        return this.endpoint;
+    }
+
+    public boolean isBrowser() {
+        return false;
+    }
+
+    public boolean isPresettle() {
+        return presettle;
+    }
+
+    public void setPresettle(boolean presettle) {
+        this.presettle = presettle;
+    }
+
+    @Override
+    public String toString() {
+        return "AmqpConsumer { " + this.info.getConsumerId() + " }";
+    }
+
+    protected void deliveryFailed(Delivery incoming, boolean expandCredit) {
+        Modified disposition = new Modified();
+        disposition.setUndeliverableHere(true);
+        disposition.setDeliveryFailed(true);
+        incoming.disposition(disposition);
+        incoming.settle();
+        if (expandCredit) {
+            endpoint.flow(1);
+        }
+    }
+
+    protected void deliver(JmsInboundMessageDispatch envelope) throws Exception {
+        ProviderListener listener = session.getProvider().getProviderListener();
+        if (listener != null) {
+            if (envelope.getMessage() != null) {
+                LOG.debug("Dispatching received message: {}", envelope.getMessage().getFacade().getMessageId());
+            } else {
+                LOG.debug("Dispatching end of browse to: {}", envelope.getConsumerId());
+            }
+            listener.onMessage(envelope);
+        } else {
+            LOG.error("Provider listener is not set, message will be dropped.");
+        }
+    }
+
+    protected EncodedMessage readIncomingMessage(Delivery incoming) {
+        Buffer buffer;
+        int count;
+
+        while ((count = endpoint.recv(incomingBuffer, 0, incomingBuffer.length)) > 0) {
+            streamBuffer.write(incomingBuffer, 0, count);
+        }
+
+        buffer = streamBuffer.toBuffer();
+
+        try {
+            return new EncodedMessage(incoming.getMessageFormat(), buffer.data, buffer.offset, buffer.length);
+        } finally {
+            streamBuffer.reset();
+        }
+    }
+
+    public void preCommit() {
+    }
+
+    public void preRollback() {
+    }
+
+    /**
+     * Ensures that all delivered messages are marked as settled locally before the TX state
+     * is cleared and the next TX started.
+     *
+     * @throws Exception if an error occurs while performing this action.
+     */
+    public void postCommit() throws Exception {
+        for (Delivery delivery : delivered.values()) {
+            delivery.settle();
+        }
+        this.delivered.clear();
+    }
+
+    /**
+     * Redeliver Acknowledge all previously delivered messages and clear state to prepare for
+     * the next TX to start.
+     *
+     * @throws Exception if an error occurs while performing this action.
+     */
+    public void postRollback() throws Exception {
+        for (Delivery delivery : delivered.values()) {
+            JmsInboundMessageDispatch envelope = (JmsInboundMessageDispatch) delivery.getContext();
+            acknowledge(envelope, ACK_TYPE.REDELIVERED);
+        }
+        this.delivered.clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpFixedProducer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpFixedProducer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpFixedProducer.java
new file mode 100644
index 0000000..a36e419
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpFixedProducer.java
@@ -0,0 +1,351 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsProducerInfo;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.provider.amqp.message.AmqpJmsMessageFacade;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.Accepted;
+import org.apache.qpid.proton.amqp.messaging.Outcome;
+import org.apache.qpid.proton.amqp.messaging.Rejected;
+import org.apache.qpid.proton.amqp.messaging.Source;
+import org.apache.qpid.proton.amqp.messaging.Target;
+import org.apache.qpid.proton.amqp.transaction.TransactionalState;
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.jms.AutoOutboundTransformer;
+import org.apache.qpid.proton.jms.EncodedMessage;
+import org.apache.qpid.proton.jms.OutboundTransformer;
+import org.apache.qpid.proton.message.Message;
+import org.fusesource.hawtbuf.Buffer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AMQP Producer object that is used to manage JMS MessageProducer semantics.
+ *
+ * This Producer is fixed to a given JmsDestination and can only produce messages to it.
+ */
+public class AmqpFixedProducer extends AmqpProducer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpFixedProducer.class);
+    private static final byte[] EMPTY_BYTE_ARRAY = new byte[] {};
+
+    private final AmqpTransferTagGenerator tagGenerator = new AmqpTransferTagGenerator(true);
+    private final Set<Delivery> pending = new LinkedHashSet<Delivery>();
+    private final LinkedList<PendingSend> pendingSends = new LinkedList<PendingSend>();
+    private byte[] encodeBuffer = new byte[1024 * 8];
+
+    private final OutboundTransformer outboundTransformer = new AutoOutboundTransformer(AmqpJMSVendor.INSTANCE);
+    private final String MESSAGE_FORMAT_KEY = outboundTransformer.getPrefixVendor() + "MESSAGE_FORMAT";
+    private boolean presettle = false;
+
+    public AmqpFixedProducer(AmqpSession session, JmsProducerInfo info) {
+        super(session, info);
+    }
+
+    @Override
+    public void close(AsyncResult request) {
+        // If any sends are held we need to wait for them to complete.
+        if (!pendingSends.isEmpty()) {
+            this.closeRequest = request;
+            return;
+        }
+
+        super.close(request);
+    }
+
+    @Override
+    public boolean send(JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException {
+
+        // TODO - Handle the case where remote has no credit which means we can't send to it.
+        //        We need to hold the send until remote credit becomes available but we should
+        //        also have a send timeout option and filter timed out sends.
+        if (endpoint.getCredit() <= 0) {
+            LOG.trace("Holding Message send until credit is available.");
+            // Once a message goes into a held mode we no longer can send it async, so
+            // we clear the async flag if set to avoid the sender never getting notified.
+            envelope.setSendAsync(false);
+            this.pendingSends.addLast(new PendingSend(envelope, request));
+            return false;
+        } else {
+            doSend(envelope, request);
+            return true;
+        }
+    }
+
+    private void doSend(JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException {
+        JmsMessageFacade facade = envelope.getMessage().getFacade();
+
+        LOG.trace("Producer sending message: {}", envelope.getMessage().getFacade().getMessageId());
+
+        byte[] tag = tagGenerator.getNextTag();
+        Delivery delivery = null;
+
+        if (presettle) {
+            delivery = endpoint.delivery(EMPTY_BYTE_ARRAY, 0, 0);
+        } else {
+            delivery = endpoint.delivery(tag, 0, tag.length);
+        }
+
+        delivery.setContext(request);
+
+        if (session.isTransacted()) {
+            Binary amqpTxId = session.getTransactionContext().getAmqpTransactionId();
+            TransactionalState state = new TransactionalState();
+            state.setTxnId(amqpTxId);
+            delivery.disposition(state);
+        }
+
+        JmsMessage message = envelope.getMessage();
+        message.setReadOnlyBody(true);
+
+        // TODO: why do we need this?
+        // Possibly because AMQP spec "2.7.5 Transfer" says message format MUST be set on at least
+        // the first Transfer frame of a message.  That is on the encoded Transfer frames though and
+        // this property isn't, but rather within the application-properties map.  We should probably
+        // ensure this elsewhere (appears Proton does so itself in TransportImpl#processTransportWorkSender)
+        if (!message.getProperties().containsKey(MESSAGE_FORMAT_KEY)) {
+            message.setProperty(MESSAGE_FORMAT_KEY, 0);
+        }
+
+        if (facade instanceof AmqpJmsMessageFacade) {
+            AmqpJmsMessageFacade amqpMessage = (AmqpJmsMessageFacade) facade;
+            encodeAndSend(amqpMessage.getAmqpMessage(), delivery);
+        } else {
+            encodeAndSend(envelope.getMessage(), delivery);
+        }
+
+        if (presettle) {
+            delivery.settle();
+        } else {
+            pending.add(delivery);
+            endpoint.advance();
+        }
+
+        if (envelope.isSendAsync() || presettle) {
+            request.onSuccess();
+        }
+    }
+
+    private void encodeAndSend(Message message, Delivery delivery) throws IOException {
+
+        int encodedSize;
+        while (true) {
+            try {
+                encodedSize = message.encode(encodeBuffer, 0, encodeBuffer.length);
+                break;
+            } catch (java.nio.BufferOverflowException e) {
+                encodeBuffer = new byte[encodeBuffer.length * 2];
+            }
+        }
+
+        Buffer sendBuffer = new Buffer(encodeBuffer, 0, encodedSize);
+
+        while (true) {
+            int sent = endpoint.send(sendBuffer.data, sendBuffer.offset, sendBuffer.length);
+            if (sent > 0) {
+                sendBuffer.moveHead(sent);
+                if (sendBuffer.length == 0) {
+                    break;
+                }
+            } else {
+                LOG.warn("{} failed to send any data from current Message.", this);
+            }
+        }
+    }
+
+    private void encodeAndSend(JmsMessage message, Delivery delivery) throws IOException {
+
+        Buffer sendBuffer = null;
+        EncodedMessage amqp = null;
+
+        try {
+            amqp = outboundTransformer.transform(message);
+        } catch (Exception e) {
+            throw IOExceptionSupport.create(e);
+        }
+
+        if (amqp != null && amqp.getLength() > 0) {
+            sendBuffer = new Buffer(amqp.getArray(), amqp.getArrayOffset(), amqp.getLength());
+        }
+
+        while (true) {
+            int sent = endpoint.send(sendBuffer.data, sendBuffer.offset, sendBuffer.length);
+            if (sent > 0) {
+                sendBuffer.moveHead(sent);
+                if (sendBuffer.length == 0) {
+                    break;
+                }
+            } else {
+                LOG.warn("{} failed to send any data from current Message.", this);
+            }
+        }
+    }
+
+    @Override
+    public void processFlowUpdates() throws IOException {
+        if (!pendingSends.isEmpty() && endpoint.getCredit() > 0) {
+            while (endpoint.getCredit() > 0 && !pendingSends.isEmpty()) {
+                LOG.trace("Dispatching previously held send");
+                PendingSend held = pendingSends.pop();
+                try {
+                    doSend(held.envelope, held.request);
+                } catch (JMSException e) {
+                    throw IOExceptionSupport.create(e);
+                }
+            }
+        }
+
+        // Once the pending sends queue is drained we can propagate the close request.
+        if (pendingSends.isEmpty() && isAwaitingClose()) {
+            super.close(closeRequest);
+        }
+    }
+
+    @Override
+    public void processDeliveryUpdates() {
+        List<Delivery> toRemove = new ArrayList<Delivery>();
+
+        for (Delivery delivery : pending) {
+            DeliveryState state = delivery.getRemoteState();
+            if (state == null) {
+                continue;
+            }
+
+            Outcome outcome = null;
+            if (state instanceof TransactionalState) {
+                LOG.trace("State of delivery is Transactional, retrieving outcome: {}", state);
+                outcome = ((TransactionalState) state).getOutcome();
+            } else if (state instanceof Outcome) {
+                outcome = (Outcome) state;
+            } else {
+                LOG.warn("Message send updated with unsupported state: {}", state);
+                continue;
+            }
+
+            AsyncResult request = (AsyncResult) delivery.getContext();
+
+            if (outcome instanceof Accepted) {
+                toRemove.add(delivery);
+                LOG.trace("Outcome of delivery was accepted: {}", delivery);
+                tagGenerator.returnTag(delivery.getTag());
+                if (request != null && !request.isComplete()) {
+                    request.onSuccess();
+                }
+            } else if (outcome instanceof Rejected) {
+                Exception remoteError = getRemoteError();
+                toRemove.add(delivery);
+                LOG.trace("Outcome of delivery was rejected: {}", delivery);
+                tagGenerator.returnTag(delivery.getTag());
+                if (request != null && !request.isComplete()) {
+                    request.onFailure(remoteError);
+                } else {
+                    connection.getProvider().fireProviderException(remoteError);
+                }
+            } else {
+                LOG.warn("Message send updated with unsupported outcome: {}", outcome);
+            }
+        }
+
+        pending.removeAll(toRemove);
+    }
+
+    @Override
+    protected void doOpen() {
+        JmsDestination destination = info.getDestination();
+
+        String destnationName = session.getQualifiedName(destination);
+        String sourceAddress = getProducerId().toString();
+        Source source = new Source();
+        source.setAddress(sourceAddress);
+        Target target = new Target();
+        target.setAddress(destnationName);
+
+        String senderName = sourceAddress + ":" + destnationName != null ? destnationName : "Anonymous";
+        endpoint = session.getProtonSession().sender(senderName);
+        endpoint.setSource(source);
+        endpoint.setTarget(target);
+        if (presettle) {
+            endpoint.setSenderSettleMode(SenderSettleMode.SETTLED);
+        } else {
+            endpoint.setSenderSettleMode(SenderSettleMode.UNSETTLED);
+        }
+        endpoint.setReceiverSettleMode(ReceiverSettleMode.FIRST);
+    }
+
+    @Override
+    protected void doClose() {
+    }
+
+    public AmqpSession getSession() {
+        return this.session;
+    }
+
+    public Sender getProtonSender() {
+        return this.endpoint;
+    }
+
+    @Override
+    public boolean isAnonymous() {
+        return false;
+    }
+
+    @Override
+    public void setPresettle(boolean presettle) {
+        this.presettle = presettle;
+    }
+
+    @Override
+    public boolean isPresettle() {
+        return this.presettle;
+    }
+
+    @Override
+    public String toString() {
+        return "AmqpFixedProducer { " + getProducerId() + " }";
+    }
+
+    private class PendingSend {
+
+        public JmsOutboundMessageDispatch envelope;
+        public AsyncResult request;
+
+        public PendingSend(JmsOutboundMessageDispatch envelope, AsyncResult request) {
+            this.envelope = envelope;
+            this.request = request;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJMSVendor.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJMSVendor.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJMSVendor.java
new file mode 100644
index 0000000..eba019e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJMSVendor.java
@@ -0,0 +1,159 @@
+/**
+ * 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.jms.provider.amqp;
+
+import javax.jms.BytesMessage;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.StreamMessage;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.TextMessage;
+import javax.jms.Topic;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.JmsTemporaryQueue;
+import org.apache.qpid.jms.JmsTemporaryTopic;
+import org.apache.qpid.jms.JmsTopic;
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.proton.jms.JMSVendor;
+
+/**
+ * Vendor instance used with Proton-J JMS Transformer bits.
+ *
+ * TODO - This can go once we have our own message wrappers all working.
+ */
+public class AmqpJMSVendor extends JMSVendor {
+
+    public static final AmqpJMSVendor INSTANCE = new AmqpJMSVendor();
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    private AmqpJMSVendor() {
+    }
+
+    @Override
+    public BytesMessage createBytesMessage() {
+        try {
+            return factory.createBytesMessage();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public StreamMessage createStreamMessage() {
+        try {
+            return factory.createStreamMessage();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public Message createMessage() {
+        try {
+            return factory.createMessage();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public TextMessage createTextMessage() {
+        try {
+            return factory.createTextMessage();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public ObjectMessage createObjectMessage() {
+        try {
+            return factory.createObjectMessage();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public MapMessage createMapMessage() {
+        try {
+            return factory.createMapMessage();
+        } catch (JMSException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public Destination createDestination(String name) {
+        return super.createDestination(name, Destination.class);
+    }
+
+    @Override
+    public <T extends Destination> T createDestination(String name, Class<T> kind) {
+        if (kind == Queue.class) {
+            return kind.cast(new JmsQueue(name));
+        }
+        if (kind == Topic.class) {
+            return kind.cast(new JmsTopic(name));
+        }
+        if (kind == TemporaryQueue.class) {
+            return kind.cast(new JmsTemporaryQueue(name));
+        }
+        if (kind == TemporaryTopic.class) {
+            return kind.cast(new JmsTemporaryTopic(name));
+        }
+
+        return kind.cast(new JmsQueue(name));
+    }
+
+    @Override
+    public void setJMSXUserID(Message msg, String value) {
+        ((JmsMessage) msg).getFacade().setUserId(value);
+    }
+
+    @Override
+    public void setJMSXGroupID(Message msg, String value) {
+        ((JmsMessage) msg).getFacade().setGroupId(value);
+    }
+
+    @Override
+    public void setJMSXGroupSequence(Message msg, int value) {
+        ((JmsMessage) msg).getFacade().setGroupSequence(value);
+    }
+
+    @Override
+    public void setJMSXDeliveryCount(Message msg, long value) {
+        // Delivery count tracks total deliveries which is always one higher than
+        // re-delivery count since first delivery counts to.
+        ((JmsMessage) msg).getFacade().setRedeliveryCounter((int) (value == 0 ? value : value - 1));
+    }
+
+    @Override
+    public String toAddress(Destination dest) {
+        return ((JmsDestination) dest).getName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsNoLocalType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsNoLocalType.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsNoLocalType.java
new file mode 100644
index 0000000..24c6286
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsNoLocalType.java
@@ -0,0 +1,44 @@
+/**
+ * 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.jms.provider.amqp;
+
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * A Described Type wrapper for JMS no local option for MessageConsumer.
+ */
+public class AmqpJmsNoLocalType implements DescribedType {
+
+    public static final AmqpJmsNoLocalType NO_LOCAL = new AmqpJmsNoLocalType();
+
+    private final String noLocal;
+
+    public AmqpJmsNoLocalType() {
+        this.noLocal = "NoLocalFilter{}";
+    }
+
+    @Override
+    public Object getDescriptor() {
+        return UnsignedLong.valueOf(0x0000468C00000003L);
+    }
+
+    @Override
+    public Object getDescribed() {
+        return this.noLocal;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsSelectorType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsSelectorType.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsSelectorType.java
new file mode 100644
index 0000000..021f943
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpJmsSelectorType.java
@@ -0,0 +1,42 @@
+/**
+ * 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.jms.provider.amqp;
+
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * A Described Type wrapper for JMS selector values.
+ */
+public class AmqpJmsSelectorType implements DescribedType {
+
+    private final String selector;
+
+    public AmqpJmsSelectorType(String selector) {
+        this.selector = selector;
+    }
+
+    @Override
+    public Object getDescriptor() {
+        return UnsignedLong.valueOf(0x0000468C00000004L);
+    }
+
+    @Override
+    public Object getDescribed() {
+        return this.selector;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProducer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProducer.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProducer.java
new file mode 100644
index 0000000..81ebf9e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProducer.java
@@ -0,0 +1,93 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsProducerId;
+import org.apache.qpid.jms.meta.JmsProducerInfo;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.proton.engine.Sender;
+
+/**
+ * Base class for Producer instances.
+ */
+public abstract class AmqpProducer extends AbstractAmqpResource<JmsProducerInfo, Sender> {
+
+    protected final AmqpSession session;
+    protected final AmqpConnection connection;
+    protected boolean presettle;
+
+    public AmqpProducer(AmqpSession session, JmsProducerInfo info) {
+        super(info);
+        this.session = session;
+        this.connection = session.getConnection();
+
+        // Add a shortcut back to this Producer for quicker lookup.
+        this.info.getProducerId().setProviderHint(this);
+    }
+
+    /**
+     * Sends the given message
+     *
+     * @param envelope
+     *        The envelope that contains the message and it's targeted destination.
+     * @param request
+     *        The AsyncRequest that will be notified on send success or failure.
+     *
+     * @returns true if the producer had credit to send or false if there was no available
+     *          credit and the send needed to be deferred.
+     *
+     * @throws IOException if an error occurs sending the message
+     * @throws JMSException if an error occurs while preparing the message for send.
+     */
+    public abstract boolean send(JmsOutboundMessageDispatch envelope, AsyncResult request) throws IOException, JMSException;
+
+    /**
+     * @return true if this is an anonymous producer or false if fixed to a given destination.
+     */
+    public abstract boolean isAnonymous();
+
+    /**
+     * @return the JmsProducerId that was assigned to this AmqpProducer.
+     */
+    public JmsProducerId getProducerId() {
+        return this.info.getProducerId();
+    }
+
+    /**
+     * @return true if the producer should presettle all sent messages.
+     */
+    public boolean isPresettle() {
+        return presettle;
+    }
+
+    /**
+     * Sets whether the producer will presettle all messages that it sends.  Sending
+     * presettled reduces the time it takes to send a message but increases the change
+     * of message loss should the connection drop during send.
+     *
+     * @param presettle
+     *        true if all messages are sent settled.
+     */
+    public void setPresettle(boolean presettle) {
+        this.presettle = presettle;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
new file mode 100644
index 0000000..aad47f1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpProvider.java
@@ -0,0 +1,821 @@
+/**
+ * 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.jms.provider.amqp;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsOutboundMessageDispatch;
+import org.apache.qpid.jms.meta.JmsConnectionInfo;
+import org.apache.qpid.jms.meta.JmsConsumerId;
+import org.apache.qpid.jms.meta.JmsConsumerInfo;
+import org.apache.qpid.jms.meta.JmsDefaultResourceVisitor;
+import org.apache.qpid.jms.meta.JmsProducerId;
+import org.apache.qpid.jms.meta.JmsProducerInfo;
+import org.apache.qpid.jms.meta.JmsResource;
+import org.apache.qpid.jms.meta.JmsResourceVistor;
+import org.apache.qpid.jms.meta.JmsSessionId;
+import org.apache.qpid.jms.meta.JmsSessionInfo;
+import org.apache.qpid.jms.meta.JmsTransactionInfo;
+import org.apache.qpid.jms.provider.AbstractProvider;
+import org.apache.qpid.jms.provider.AsyncResult;
+import org.apache.qpid.jms.provider.ProviderFuture;
+import org.apache.qpid.jms.provider.ProviderConstants.ACK_TYPE;
+import org.apache.qpid.jms.transports.TcpTransport;
+import org.apache.qpid.jms.transports.TransportListener;
+import org.apache.qpid.jms.util.IOExceptionSupport;
+import org.apache.qpid.jms.util.PropertyUtil;
+import org.apache.qpid.proton.engine.Collector;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.Event;
+import org.apache.qpid.proton.engine.Event.Type;
+import org.apache.qpid.proton.engine.Sasl;
+import org.apache.qpid.proton.engine.Transport;
+import org.apache.qpid.proton.engine.impl.CollectorImpl;
+import org.apache.qpid.proton.engine.impl.ProtocolTracer;
+import org.apache.qpid.proton.engine.impl.TransportImpl;
+import org.apache.qpid.proton.framing.TransportFrame;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.vertx.java.core.buffer.Buffer;
+
+/**
+ * An AMQP v1.0 Provider.
+ *
+ * The AMQP Provider is bonded to a single remote broker instance.  The provider will attempt
+ * to connect to only that instance and once failed can not be recovered.  For clients that
+ * wish to implement failover type connections a new AMQP Provider instance must be created
+ * and state replayed from the JMS layer using the standard recovery process defined in the
+ * JMS Provider API.
+ *
+ * All work within this Provider is serialized to a single Thread.  Any asynchronous exceptions
+ * will be dispatched from that Thread and all in-bound requests are handled there as well.
+ */
+public class AmqpProvider extends AbstractProvider implements TransportListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AmqpProvider.class);
+
+    private static final Logger TRACE_BYTES = LoggerFactory.getLogger(AmqpConnection.class.getPackage().getName() + ".BYTES");
+    private static final Logger TRACE_FRAMES = LoggerFactory.getLogger(AmqpConnection.class.getPackage().getName() + ".FRAMES");
+    private static final int DEFAULT_MAX_FRAME_SIZE = 1024 * 1024 * 1;
+
+    private AmqpConnection connection;
+    private org.apache.qpid.jms.transports.Transport transport;
+    private boolean traceFrames;
+    private boolean traceBytes;
+    private boolean presettleConsumers;
+    private boolean presettleProducers;
+    private long connectTimeout = JmsConnectionInfo.DEFAULT_CONNECT_TIMEOUT;
+    private long closeTimeout = JmsConnectionInfo.DEFAULT_CLOSE_TIMEOUT;
+    private long requestTimeout = JmsConnectionInfo.DEFAULT_REQUEST_TIMEOUT;
+    private long sendTimeout = JmsConnectionInfo.DEFAULT_SEND_TIMEOUT;
+
+    private final Transport protonTransport = Transport.Factory.create();
+    private final Collector protonCollector = new CollectorImpl();
+
+    /**
+     * Create a new instance of an AmqpProvider bonded to the given remote URI.
+     *
+     * @param remoteURI
+     *        The URI of the AMQP broker this Provider instance will connect to.
+     */
+    public AmqpProvider(URI remoteURI) {
+        this(remoteURI, null);
+    }
+
+    /**
+     * Create a new instance of an AmqpProvider bonded to the given remote URI.
+     *
+     * @param remoteURI
+     *        The URI of the AMQP broker this Provider instance will connect to.
+     */
+    public AmqpProvider(URI remoteURI, Map<String, String> extraOptions) {
+        super(remoteURI);
+        updateTracer();
+    }
+
+    @Override
+    public void connect() throws IOException {
+        checkClosed();
+
+        transport = createTransport(getRemoteURI());
+
+        Map<String, String> map = Collections.emptyMap();
+        try {
+            map = PropertyUtil.parseQuery(remoteURI.getQuery());
+        } catch (Exception e) {
+            IOExceptionSupport.create(e);
+        }
+        Map<String, String> providerOptions = PropertyUtil.filterProperties(map, "transport.");
+
+        if (!PropertyUtil.setProperties(transport, providerOptions)) {
+            String msg = ""
+                + " Not all transport options could be set on the AMQP Provider transport."
+                + " Check the options are spelled correctly."
+                + " Given parameters=[" + providerOptions + "]."
+                + " This provider instance cannot be started.";
+            throw new IOException(msg);
+        }
+
+        transport.connect();
+    }
+
+    @Override
+    public void close() {
+        if (closed.compareAndSet(false, true)) {
+            final ProviderFuture request = new ProviderFuture();
+            serializer.execute(new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+
+                        // If we are not connected then there is nothing we can do now
+                        // just signal success.
+                        if (!transport.isConnected()) {
+                            request.onSuccess();
+                        }
+
+                        if (connection != null) {
+                            connection.close(request);
+                        } else {
+                            request.onSuccess();
+                        }
+
+                        pumpToProtonTransport();
+                    } catch (Exception e) {
+                        LOG.debug("Caught exception while closing proton connection");
+                    }
+                }
+            });
+
+            try {
+                if (closeTimeout < 0) {
+                    request.sync();
+                } else {
+                    request.sync(closeTimeout, TimeUnit.MILLISECONDS);
+                }
+            } catch (IOException e) {
+                LOG.warn("Error caught while closing Provider: ", e.getMessage());
+            } finally {
+                if (transport != null) {
+                    try {
+                        transport.close();
+                    } catch (Exception e) {
+                        LOG.debug("Cuaght exception while closing down Transport: {}", e.getMessage());
+                    }
+                }
+
+                if (serializer != null) {
+                    serializer.shutdown();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void create(final JmsResource resource, final AsyncResult request) throws IOException, JMSException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    resource.visit(new JmsResourceVistor() {
+
+                        @Override
+                        public void processSessionInfo(JmsSessionInfo sessionInfo) throws Exception {
+                            AmqpSession session = connection.createSession(sessionInfo);
+                            session.open(request);
+                        }
+
+                        @Override
+                        public void processProducerInfo(JmsProducerInfo producerInfo) throws Exception {
+                            AmqpSession session = connection.getSession(producerInfo.getParentId());
+                            AmqpProducer producer = session.createProducer(producerInfo);
+                            producer.open(request);
+                        }
+
+                        @Override
+                        public void processConsumerInfo(JmsConsumerInfo consumerInfo) throws Exception {
+                            AmqpSession session = connection.getSession(consumerInfo.getParentId());
+                            AmqpConsumer consumer = session.createConsumer(consumerInfo);
+                            consumer.open(request);
+                        }
+
+                        @Override
+                        public void processConnectionInfo(JmsConnectionInfo connectionInfo) throws Exception {
+                            closeTimeout = connectionInfo.getCloseTimeout();
+                            connectTimeout = connectionInfo.getConnectTimeout();
+                            sendTimeout = connectionInfo.getSendTimeout();
+                            requestTimeout = connectionInfo.getRequestTimeout();
+
+                            Connection protonConnection = Connection.Factory.create();
+                            protonTransport.setMaxFrameSize(getMaxFrameSize());
+                            protonTransport.bind(protonConnection);
+                            protonConnection.collect(protonCollector);
+                            Sasl sasl = protonTransport.sasl();
+                            if (sasl != null) {
+                                sasl.client();
+                            }
+                            connection = new AmqpConnection(AmqpProvider.this, protonConnection, sasl, connectionInfo);
+                            connection.open(request);
+                        }
+
+                        @Override
+                        public void processDestination(JmsDestination destination) throws Exception {
+                            if (destination.isTemporary()) {
+                                AmqpTemporaryDestination temporary = connection.createTemporaryDestination(destination);
+                                temporary.open(request);
+                            } else {
+                                request.onSuccess();
+                            }
+                        }
+
+                        @Override
+                        public void processTransactionInfo(JmsTransactionInfo transactionInfo) throws Exception {
+                            AmqpSession session = connection.getSession(transactionInfo.getParentId());
+                            session.begin(transactionInfo.getTransactionId(), request);
+                        }
+                    });
+
+                    pumpToProtonTransport();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void start(final JmsResource resource, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    resource.visit(new JmsDefaultResourceVisitor() {
+
+                        @Override
+                        public void processConsumerInfo(JmsConsumerInfo consumerInfo) throws Exception {
+                            AmqpSession session = connection.getSession(consumerInfo.getParentId());
+                            AmqpConsumer consumer = session.getConsumer(consumerInfo);
+                            consumer.start(request);
+                        }
+                    });
+
+                    pumpToProtonTransport();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void destroy(final JmsResource resource, final AsyncResult request) throws IOException {
+        //TODO: improve or delete this logging
+        LOG.debug("Destroy called");
+
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    //TODO: improve or delete this logging
+                    LOG.debug("Processing resource destroy request");
+                    checkClosed();
+                    resource.visit(new JmsDefaultResourceVisitor() {
+
+                        @Override
+                        public void processSessionInfo(JmsSessionInfo sessionInfo) throws Exception {
+                            AmqpSession session = connection.getSession(sessionInfo.getSessionId());
+                            session.close(request);
+                        }
+
+                        @Override
+                        public void processProducerInfo(JmsProducerInfo producerInfo) throws Exception {
+                            AmqpSession session = connection.getSession(producerInfo.getParentId());
+                            AmqpProducer producer = session.getProducer(producerInfo);
+                            producer.close(request);
+                        }
+
+                        @Override
+                        public void processConsumerInfo(JmsConsumerInfo consumerInfo) throws Exception {
+                            AmqpSession session = connection.getSession(consumerInfo.getParentId());
+                            AmqpConsumer consumer = session.getConsumer(consumerInfo);
+                            consumer.close(request);
+                        }
+
+                        @Override
+                        public void processConnectionInfo(JmsConnectionInfo connectionInfo) throws Exception {
+                            connection.close(request);
+                        }
+
+                        @Override
+                        public void processDestination(JmsDestination destination) throws Exception {
+                            // TODO - Delete remote temporary Topic or Queue
+                            request.onSuccess();
+                        }
+                    });
+
+                    pumpToProtonTransport();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void send(final JmsOutboundMessageDispatch envelope, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+
+                    JmsProducerId producerId = envelope.getProducerId();
+                    AmqpProducer producer = null;
+
+                    if (producerId.getProviderHint() instanceof AmqpFixedProducer) {
+                        producer = (AmqpFixedProducer) producerId.getProviderHint();
+                    } else {
+                        AmqpSession session = connection.getSession(producerId.getParentId());
+                        producer = session.getProducer(producerId);
+                    }
+
+                    boolean couldSend = producer.send(envelope, request);
+                    pumpToProtonTransport();
+                    if (couldSend && envelope.isSendAsync()) {
+                        request.onSuccess();
+                    }
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void acknowledge(final JmsSessionId sessionId, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    AmqpSession amqpSession = connection.getSession(sessionId);
+                    amqpSession.acknowledge();
+                    pumpToProtonTransport();
+                    request.onSuccess();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void acknowledge(final JmsInboundMessageDispatch envelope, final ACK_TYPE ackType, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+
+                    JmsConsumerId consumerId = envelope.getConsumerId();
+                    AmqpConsumer consumer = null;
+
+                    if (consumerId.getProviderHint() instanceof AmqpConsumer) {
+                        consumer = (AmqpConsumer) consumerId.getProviderHint();
+                    } else {
+                        AmqpSession session = connection.getSession(consumerId.getParentId());
+                        consumer = session.getConsumer(consumerId);
+                    }
+
+                    consumer.acknowledge(envelope, ackType);
+
+                    if (consumer.getSession().isAsyncAck()) {
+                        request.onSuccess();
+                        pumpToProtonTransport();
+                    } else {
+                        pumpToProtonTransport();
+                        request.onSuccess();
+                    }
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void commit(final JmsSessionId sessionId, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    AmqpSession session = connection.getSession(sessionId);
+                    session.commit(request);
+                    pumpToProtonTransport();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void rollback(final JmsSessionId sessionId, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    AmqpSession session = connection.getSession(sessionId);
+                    session.rollback(request);
+                    pumpToProtonTransport();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void recover(final JmsSessionId sessionId, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    AmqpSession session = connection.getSession(sessionId);
+                    session.recover();
+                    pumpToProtonTransport();
+                    request.onSuccess();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void unsubscribe(final String subscription, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    pumpToProtonTransport();
+                    request.onSuccess();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void pull(final JmsConsumerId consumerId, final long timeout, final AsyncResult request) throws IOException {
+        checkClosed();
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    checkClosed();
+                    AmqpConsumer consumer = null;
+
+                    if (consumerId.getProviderHint() instanceof AmqpConsumer) {
+                        consumer = (AmqpConsumer) consumerId.getProviderHint();
+                    } else {
+                        AmqpSession session = connection.getSession(consumerId.getParentId());
+                        consumer = session.getConsumer(consumerId);
+                    }
+
+                    consumer.pull(timeout);
+                    pumpToProtonTransport();
+                    request.onSuccess();
+                } catch (Exception error) {
+                    request.onFailure(error);
+                }
+            }
+        });
+    }
+
+    /**
+     * Provides an extension point for subclasses to insert other types of transports such
+     * as SSL etc.
+     *
+     * @param remoteLocation
+     *        The remote location where the transport should attempt to connect.
+     *
+     * @return the newly created transport instance.
+     */
+    protected org.apache.qpid.jms.transports.Transport createTransport(URI remoteLocation) {
+        return new TcpTransport(this, remoteLocation);
+    }
+
+    private void updateTracer() {
+        if (isTraceFrames()) {
+            ((TransportImpl) protonTransport).setProtocolTracer(new ProtocolTracer() {
+                @Override
+                public void receivedFrame(TransportFrame transportFrame) {
+                    TRACE_FRAMES.trace("RECV: {}", transportFrame.getBody());
+                }
+
+                @Override
+                public void sentFrame(TransportFrame transportFrame) {
+                    TRACE_FRAMES.trace("SENT: {}", transportFrame.getBody());
+                }
+            });
+        }
+    }
+
+    @Override
+    public void onData(Buffer input) {
+
+        // Create our own copy since we will process later.
+        final ByteBuffer source = ByteBuffer.wrap(input.getBytes());
+
+        serializer.execute(new Runnable() {
+
+            @Override
+            public void run() {
+                LOG.trace("Received from Broker {} bytes:", source.remaining());
+
+                do {
+                    ByteBuffer buffer = protonTransport.getInputBuffer();
+                    int limit = Math.min(buffer.remaining(), source.remaining());
+                    ByteBuffer duplicate = source.duplicate();
+                    duplicate.limit(source.position() + limit);
+                    buffer.put(duplicate);
+                    protonTransport.processInput();
+                    source.position(source.position() + limit);
+                } while (source.hasRemaining());
+
+                // Process the state changes from the latest data and then answer back
+                // any pending updates to the Broker.
+                processUpdates();
+                pumpToProtonTransport();
+            }
+        });
+    }
+
+    /**
+     * Callback method for the Transport to report connection errors.  When called
+     * the method will queue a new task to fire the failure error back to the listener.
+     *
+     * @param error
+     *        the error that causes the transport to fail.
+     */
+    @Override
+    public void onTransportError(final Throwable error) {
+        if (!serializer.isShutdown()) {
+            serializer.execute(new Runnable() {
+                @Override
+                public void run() {
+                    LOG.info("Transport failed: {}", error.getMessage());
+                    if (!closed.get()) {
+                        fireProviderException(error);
+                        if (connection != null) {
+                            connection.closed();
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    /**
+     * Callback method for the Transport to report that the underlying connection
+     * has closed.  When called this method will queue a new task that will check for
+     * the closed state on this transport and if not closed then an exception is raied
+     * to the registered ProviderListener to indicate connection loss.
+     */
+    @Override
+    public void onTransportClosed() {
+        // TODO: improve or delete this logging
+        LOG.debug("onTransportClosed listener called");
+        if (!serializer.isShutdown()) {
+            serializer.execute(new Runnable() {
+                @Override
+                public void run() {
+                    LOG.debug("Transport connection remotely closed");
+                    if (!closed.get()) {
+                        fireProviderException(new IOException("Connection remotely closed."));
+                        if (connection != null) {
+                            connection.closed();
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    private void processUpdates() {
+        try {
+            Event protonEvent = null;
+            while ((protonEvent = protonCollector.peek()) != null) {
+                if (!protonEvent.getType().equals(Type.TRANSPORT)) {
+                    LOG.trace("New Proton Event: {}", protonEvent.getType());
+                }
+
+                AmqpResource amqpResource = null;
+                switch (protonEvent.getType()) {
+                    case CONNECTION_REMOTE_CLOSE:
+                    case CONNECTION_REMOTE_OPEN:
+                        AmqpConnection connection = (AmqpConnection) protonEvent.getConnection().getContext();
+                        connection.processStateChange();
+                        break;
+                    case SESSION_REMOTE_CLOSE:
+                    case SESSION_REMOTE_OPEN:
+                        AmqpSession session = (AmqpSession) protonEvent.getSession().getContext();
+                        session.processStateChange();
+                        break;
+                    case LINK_REMOTE_CLOSE:
+                    case LINK_REMOTE_OPEN:
+                        AmqpResource resource = (AmqpResource) protonEvent.getLink().getContext();
+                        resource.processStateChange();
+                        break;
+                    case LINK_FLOW:
+                        amqpResource = (AmqpResource) protonEvent.getLink().getContext();
+                        amqpResource.processFlowUpdates();
+                        break;
+                    case DELIVERY:
+                        amqpResource = (AmqpResource) protonEvent.getLink().getContext();
+                        amqpResource.processDeliveryUpdates();
+                        break;
+                    default:
+                        break;
+                }
+
+                protonCollector.pop();
+            }
+
+            // We have to do this to pump SASL bytes in as SASL is not event driven yet.
+            if (connection != null) {
+                connection.processSaslAuthentication();
+            }
+        } catch (Exception ex) {
+            LOG.warn("Caught Exception during update processing: {}", ex.getMessage(), ex);
+            fireProviderException(ex);
+        }
+    }
+
+    private void pumpToProtonTransport() {
+        try {
+            boolean done = false;
+            while (!done) {
+                ByteBuffer toWrite = protonTransport.getOutputBuffer();
+                if (toWrite != null && toWrite.hasRemaining()) {
+                    // TODO - Get Bytes in a readable form
+                    if (isTraceBytes()) {
+                        TRACE_BYTES.info("Sending: {}", toWrite.toString());
+                    }
+                    transport.send(toWrite);
+                    protonTransport.outputConsumed();
+                } else {
+                    done = true;
+                }
+            }
+        } catch (IOException e) {
+            fireProviderException(e);
+        }
+    }
+
+    //---------- Property Setters and Getters --------------------------------//
+
+    @Override
+    public JmsMessageFactory getMessageFactory() {
+        if (connection == null) {
+            throw new RuntimeException("Message Factory is not accessible when not connected.");
+        }
+        return connection.getAmqpMessageFactory();
+    }
+
+    public void setTraceFrames(boolean trace) {
+        this.traceFrames = trace;
+        updateTracer();
+    }
+
+    public boolean isTraceFrames() {
+        return this.traceFrames;
+    }
+
+    public void setTraceBytes(boolean trace) {
+        this.traceBytes = trace;
+    }
+
+    public boolean isTraceBytes() {
+        return this.traceBytes;
+    }
+
+    public long getCloseTimeout() {
+        return this.closeTimeout;
+    }
+
+    public void setCloseTimeout(long closeTimeout) {
+        this.closeTimeout = closeTimeout;
+    }
+
+    public long getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(long connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public long getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    public void setRequestTimeout(long requestTimeout) {
+        this.requestTimeout = requestTimeout;
+    }
+
+    public long getSendTimeout() {
+        return sendTimeout;
+    }
+
+    public void setSendTimeout(long sendTimeout) {
+        this.sendTimeout = sendTimeout;
+    }
+
+    public void setPresettle(boolean presettle) {
+        setPresettleConsumers(presettle);
+        setPresettleProducers(presettle);
+    }
+
+    public boolean isPresettleConsumers() {
+        return this.presettleConsumers;
+    }
+
+    public void setPresettleConsumers(boolean presettle) {
+        this.presettleConsumers = presettle;
+    }
+
+    public boolean isPresettleProducers() {
+        return this.presettleProducers;
+    }
+
+    public void setPresettleProducers(boolean presettle) {
+        this.presettleProducers = presettle;
+    }
+
+    /**
+     * @return the currently set Max Frame Size value.
+     */
+    public int getMaxFrameSize() {
+        return DEFAULT_MAX_FRAME_SIZE;
+    }
+
+    @Override
+    public String toString() {
+        return "AmqpProvider: " + getRemoteURI().getHost() + ":" + getRemoteURI().getPort();
+    }
+}


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


[08/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/BeginFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/BeginFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/BeginFrame.java
new file mode 100644
index 0000000..b350fd1
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/BeginFrame.java
@@ -0,0 +1,110 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class BeginFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:begin:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000011L);
+
+
+    private static final int FIELD_REMOTE_CHANNEL = 0;
+    private static final int FIELD_NEXT_OUTGOING_ID = 1;
+    private static final int FIELD_INCOMING_WINDOW = 2;
+    private static final int FIELD_OUTGOING_WINDOW = 3;
+    private static final int FIELD_HANDLE_MAX = 4;
+    private static final int FIELD_OFFERED_CAPABILITIES = 5;
+    private static final int FIELD_DESIRED_CAPABILITIES = 6;
+    private static final int FIELD_PROPERTIES = 7;
+
+    public BeginFrame(Object... fields)
+    {
+        super(8);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public BeginFrame setRemoteChannel(Object o)
+    {
+        getFields()[FIELD_REMOTE_CHANNEL] = o;
+        return this;
+    }
+
+    public BeginFrame setNextOutgoingId(Object o)
+    {
+        getFields()[FIELD_NEXT_OUTGOING_ID] = o;
+        return this;
+    }
+
+    public BeginFrame setIncomingWindow(Object o)
+    {
+        getFields()[FIELD_INCOMING_WINDOW] = o;
+        return this;
+    }
+
+    public BeginFrame setOutgoingWindow(Object o)
+    {
+        getFields()[FIELD_OUTGOING_WINDOW] = o;
+        return this;
+    }
+
+    public BeginFrame setHandleMax(Object o)
+    {
+        getFields()[FIELD_HANDLE_MAX] = o;
+        return this;
+    }
+
+    public BeginFrame setOfferedCapabilities(Object o)
+    {
+        getFields()[FIELD_OFFERED_CAPABILITIES] = o;
+        return this;
+    }
+
+    public BeginFrame setDesiredCapabilities(Object o)
+    {
+        getFields()[FIELD_DESIRED_CAPABILITIES] = o;
+        return this;
+    }
+
+    public BeginFrame setProperties(Object o)
+    {
+        getFields()[FIELD_PROPERTIES] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/CloseFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/CloseFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/CloseFrame.java
new file mode 100644
index 0000000..b513de9
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/CloseFrame.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class CloseFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:close:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000018L);
+
+
+    private static final int FIELD_ERROR = 0;
+
+    public CloseFrame(Object... fields)
+    {
+        super(1);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public CloseFrame setError(Object o)
+    {
+        getFields()[FIELD_ERROR] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DetachFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DetachFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DetachFrame.java
new file mode 100644
index 0000000..443e59e
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DetachFrame.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class DetachFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:detach:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000016L);
+
+
+    private static final int FIELD_HANDLE = 0;
+    private static final int FIELD_CLOSED = 1;
+    private static final int FIELD_ERROR = 2;
+
+    public DetachFrame(Object... fields)
+    {
+        super(3);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public DetachFrame setHandle(Object o)
+    {
+        getFields()[FIELD_HANDLE] = o;
+        return this;
+    }
+
+    public DetachFrame setClosed(Object o)
+    {
+        getFields()[FIELD_CLOSED] = o;
+        return this;
+    }
+
+    public DetachFrame setError(Object o)
+    {
+        getFields()[FIELD_ERROR] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DispositionFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DispositionFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DispositionFrame.java
new file mode 100644
index 0000000..385dc9d
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/DispositionFrame.java
@@ -0,0 +1,96 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class DispositionFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:disposition:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000015L);
+
+
+    private static final int FIELD_ROLE = 0;
+    private static final int FIELD_FIRST = 1;
+    private static final int FIELD_LAST = 2;
+    private static final int FIELD_SETTLED = 3;
+    private static final int FIELD_STATE = 4;
+    private static final int FIELD_BATCHABLE = 5;
+
+    public DispositionFrame(Object... fields)
+    {
+        super(6);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public DispositionFrame setRole(Object o)
+    {
+        getFields()[FIELD_ROLE] = o;
+        return this;
+    }
+
+    public DispositionFrame setFirst(Object o)
+    {
+        getFields()[FIELD_FIRST] = o;
+        return this;
+    }
+
+    public DispositionFrame setLast(Object o)
+    {
+        getFields()[FIELD_LAST] = o;
+        return this;
+    }
+
+    public DispositionFrame setSettled(Object o)
+    {
+        getFields()[FIELD_SETTLED] = o;
+        return this;
+    }
+
+    public DispositionFrame setState(Object o)
+    {
+        getFields()[FIELD_STATE] = o;
+        return this;
+    }
+
+    public DispositionFrame setBatchable(Object o)
+    {
+        getFields()[FIELD_BATCHABLE] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/EndFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/EndFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/EndFrame.java
new file mode 100644
index 0000000..ee54a04
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/EndFrame.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class EndFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:end:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000017L);
+
+
+    private static final int FIELD_ERROR = 0;
+
+    public EndFrame(Object... fields)
+    {
+        super(1);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public EndFrame setError(Object o)
+    {
+        getFields()[FIELD_ERROR] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/FlowFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/FlowFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/FlowFrame.java
new file mode 100644
index 0000000..bd4411d
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/FlowFrame.java
@@ -0,0 +1,131 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class FlowFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:flow:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000013L);
+
+
+    private static final int FIELD_NEXT_INCOMING_ID = 0;
+    private static final int FIELD_INCOMING_WINDOW = 1;
+    private static final int FIELD_NEXT_OUTGOING_ID = 2;
+    private static final int FIELD_OUTGOING_WINDOW = 3;
+    private static final int FIELD_HANDLE = 4;
+    private static final int FIELD_DELIVERY_COUNT = 5;
+    private static final int FIELD_LINK_CREDIT = 6;
+    private static final int FIELD_AVAILABLE = 7;
+    private static final int FIELD_DRAIN = 8;
+    private static final int FIELD_ECHO = 9;
+    private static final int FIELD_PROPERTIES = 10;
+
+    public FlowFrame(Object... fields)
+    {
+        super(11);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public FlowFrame setNextIncomingId(Object o)
+    {
+        getFields()[FIELD_NEXT_INCOMING_ID] = o;
+        return this;
+    }
+
+    public FlowFrame setIncomingWindow(Object o)
+    {
+        getFields()[FIELD_INCOMING_WINDOW] = o;
+        return this;
+    }
+
+    public FlowFrame setNextOutgoingId(Object o)
+    {
+        getFields()[FIELD_NEXT_OUTGOING_ID] = o;
+        return this;
+    }
+
+    public FlowFrame setOutgoingWindow(Object o)
+    {
+        getFields()[FIELD_OUTGOING_WINDOW] = o;
+        return this;
+    }
+
+    public FlowFrame setHandle(Object o)
+    {
+        getFields()[FIELD_HANDLE] = o;
+        return this;
+    }
+
+    public FlowFrame setDeliveryCount(Object o)
+    {
+        getFields()[FIELD_DELIVERY_COUNT] = o;
+        return this;
+    }
+
+    public FlowFrame setLinkCredit(Object o)
+    {
+        getFields()[FIELD_LINK_CREDIT] = o;
+        return this;
+    }
+
+    public FlowFrame setAvailable(Object o)
+    {
+        getFields()[FIELD_AVAILABLE] = o;
+        return this;
+    }
+
+    public FlowFrame setDrain(Object o)
+    {
+        getFields()[FIELD_DRAIN] = o;
+        return this;
+    }
+
+    public FlowFrame setEcho(Object o)
+    {
+        getFields()[FIELD_ECHO] = o;
+        return this;
+    }
+
+    public FlowFrame setProperties(Object o)
+    {
+        getFields()[FIELD_PROPERTIES] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Modified.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Modified.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Modified.java
new file mode 100644
index 0000000..d934106
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Modified.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class Modified extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:modified:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000027L);
+
+
+    private static final int FIELD_DELIVERY_FAILED = 0;
+    private static final int FIELD_UNDELIVERABLE_HERE = 1;
+    private static final int FIELD_MESSAGE_ANNOTATIONS = 2;
+
+    public Modified(Object... fields)
+    {
+        super(3);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public Modified setDeliveryFailed(Object o)
+    {
+        getFields()[FIELD_DELIVERY_FAILED] = o;
+        return this;
+    }
+
+    public Modified setUndeliverableHere(Object o)
+    {
+        getFields()[FIELD_UNDELIVERABLE_HERE] = o;
+        return this;
+    }
+
+    public Modified setMessageAnnotations(Object o)
+    {
+        getFields()[FIELD_MESSAGE_ANNOTATIONS] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/OpenFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/OpenFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/OpenFrame.java
new file mode 100644
index 0000000..a89af0e
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/OpenFrame.java
@@ -0,0 +1,124 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class OpenFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:open:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000010L);
+
+
+    private static final int FIELD_CONTAINER_ID = 0;
+    private static final int FIELD_HOSTNAME = 1;
+    private static final int FIELD_MAX_FRAME_SIZE = 2;
+    private static final int FIELD_CHANNEL_MAX = 3;
+    private static final int FIELD_IDLE_TIME_OUT = 4;
+    private static final int FIELD_OUTGOING_LOCALES = 5;
+    private static final int FIELD_INCOMING_LOCALES = 6;
+    private static final int FIELD_OFFERED_CAPABILITIES = 7;
+    private static final int FIELD_DESIRED_CAPABILITIES = 8;
+    private static final int FIELD_PROPERTIES = 9;
+
+    public OpenFrame(Object... fields)
+    {
+        super(10);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public OpenFrame setContainerId(Object o)
+    {
+        getFields()[FIELD_CONTAINER_ID] = o;
+        return this;
+    }
+
+    public OpenFrame setHostname(Object o)
+    {
+        getFields()[FIELD_HOSTNAME] = o;
+        return this;
+    }
+
+    public OpenFrame setMaxFrameSize(Object o)
+    {
+        getFields()[FIELD_MAX_FRAME_SIZE] = o;
+        return this;
+    }
+
+    public OpenFrame setChannelMax(Object o)
+    {
+        getFields()[FIELD_CHANNEL_MAX] = o;
+        return this;
+    }
+
+    public OpenFrame setIdleTimeOut(Object o)
+    {
+        getFields()[FIELD_IDLE_TIME_OUT] = o;
+        return this;
+    }
+
+    public OpenFrame setOutgoingLocales(Object o)
+    {
+        getFields()[FIELD_OUTGOING_LOCALES] = o;
+        return this;
+    }
+
+    public OpenFrame setIncomingLocales(Object o)
+    {
+        getFields()[FIELD_INCOMING_LOCALES] = o;
+        return this;
+    }
+
+    public OpenFrame setOfferedCapabilities(Object o)
+    {
+        getFields()[FIELD_OFFERED_CAPABILITIES] = o;
+        return this;
+    }
+
+    public OpenFrame setDesiredCapabilities(Object o)
+    {
+        getFields()[FIELD_DESIRED_CAPABILITIES] = o;
+        return this;
+    }
+
+    public OpenFrame setProperties(Object o)
+    {
+        getFields()[FIELD_PROPERTIES] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Rejected.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Rejected.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Rejected.java
new file mode 100644
index 0000000..817576f
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Rejected.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class Rejected extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:rejected:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000025L);
+
+
+    private static final int FIELD_ERROR = 0;
+
+    public Rejected(Object... fields)
+    {
+        super(1);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public Rejected setError(Object o)
+    {
+        getFields()[FIELD_ERROR] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Released.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Released.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Released.java
new file mode 100644
index 0000000..5925265
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Released.java
@@ -0,0 +1,54 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class Released extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:released:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000026L);
+
+
+
+    public Released(Object... fields)
+    {
+        super(0);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslChallengeFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslChallengeFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslChallengeFrame.java
new file mode 100644
index 0000000..c8033eb
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslChallengeFrame.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class SaslChallengeFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:sasl-challenge:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000042L);
+
+
+    private static final int FIELD_CHALLENGE = 0;
+
+    public SaslChallengeFrame(Object... fields)
+    {
+        super(1);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public SaslChallengeFrame setChallenge(Object o)
+    {
+        getFields()[FIELD_CHALLENGE] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslInitFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslInitFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslInitFrame.java
new file mode 100644
index 0000000..a11ce3d
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslInitFrame.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class SaslInitFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:sasl-init:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000041L);
+
+
+    private static final int FIELD_MECHANISM = 0;
+    private static final int FIELD_INITIAL_RESPONSE = 1;
+    private static final int FIELD_HOSTNAME = 2;
+
+    public SaslInitFrame(Object... fields)
+    {
+        super(3);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public SaslInitFrame setMechanism(Object o)
+    {
+        getFields()[FIELD_MECHANISM] = o;
+        return this;
+    }
+
+    public SaslInitFrame setInitialResponse(Object o)
+    {
+        getFields()[FIELD_INITIAL_RESPONSE] = o;
+        return this;
+    }
+
+    public SaslInitFrame setHostname(Object o)
+    {
+        getFields()[FIELD_HOSTNAME] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslMechanismsFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslMechanismsFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslMechanismsFrame.java
new file mode 100644
index 0000000..40bf99d
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslMechanismsFrame.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class SaslMechanismsFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:sasl-mechanisms:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000040L);
+
+
+    private static final int FIELD_SASL_SERVER_MECHANISMS = 0;
+
+    public SaslMechanismsFrame(Object... fields)
+    {
+        super(1);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public SaslMechanismsFrame setSaslServerMechanisms(Object o)
+    {
+        getFields()[FIELD_SASL_SERVER_MECHANISMS] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslOutcomeFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslOutcomeFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslOutcomeFrame.java
new file mode 100644
index 0000000..27da943
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslOutcomeFrame.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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class SaslOutcomeFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:sasl-outcome:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000044L);
+
+
+    private static final int FIELD_CODE = 0;
+    private static final int FIELD_ADDITIONAL_DATA = 1;
+
+    public SaslOutcomeFrame(Object... fields)
+    {
+        super(2);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public SaslOutcomeFrame setCode(Object o)
+    {
+        getFields()[FIELD_CODE] = o;
+        return this;
+    }
+
+    public SaslOutcomeFrame setAdditionalData(Object o)
+    {
+        getFields()[FIELD_ADDITIONAL_DATA] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslResponseFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslResponseFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslResponseFrame.java
new file mode 100644
index 0000000..94e6094
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/SaslResponseFrame.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class SaslResponseFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:sasl-response:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000043L);
+
+
+    private static final int FIELD_RESPONSE = 0;
+
+    public SaslResponseFrame(Object... fields)
+    {
+        super(1);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public SaslResponseFrame setResponse(Object o)
+    {
+        getFields()[FIELD_RESPONSE] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Source.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Source.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Source.java
new file mode 100644
index 0000000..a2b0683
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Source.java
@@ -0,0 +1,131 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class Source extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:source:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000028L);
+
+
+    private static final int FIELD_ADDRESS = 0;
+    private static final int FIELD_DURABLE = 1;
+    private static final int FIELD_EXPIRY_POLICY = 2;
+    private static final int FIELD_TIMEOUT = 3;
+    private static final int FIELD_DYNAMIC = 4;
+    private static final int FIELD_DYNAMIC_NODE_PROPERTIES = 5;
+    private static final int FIELD_DISTRIBUTION_MODE = 6;
+    private static final int FIELD_FILTER = 7;
+    private static final int FIELD_DEFAULT_OUTCOME = 8;
+    private static final int FIELD_OUTCOMES = 9;
+    private static final int FIELD_CAPABILITIES = 10;
+
+    public Source(Object... fields)
+    {
+        super(11);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public Source setAddress(Object o)
+    {
+        getFields()[FIELD_ADDRESS] = o;
+        return this;
+    }
+
+    public Source setDurable(Object o)
+    {
+        getFields()[FIELD_DURABLE] = o;
+        return this;
+    }
+
+    public Source setExpiryPolicy(Object o)
+    {
+        getFields()[FIELD_EXPIRY_POLICY] = o;
+        return this;
+    }
+
+    public Source setTimeout(Object o)
+    {
+        getFields()[FIELD_TIMEOUT] = o;
+        return this;
+    }
+
+    public Source setDynamic(Object o)
+    {
+        getFields()[FIELD_DYNAMIC] = o;
+        return this;
+    }
+
+    public Source setDynamicNodeProperties(Object o)
+    {
+        getFields()[FIELD_DYNAMIC_NODE_PROPERTIES] = o;
+        return this;
+    }
+
+    public Source setDistributionMode(Object o)
+    {
+        getFields()[FIELD_DISTRIBUTION_MODE] = o;
+        return this;
+    }
+
+    public Source setFilter(Object o)
+    {
+        getFields()[FIELD_FILTER] = o;
+        return this;
+    }
+
+    public Source setDefaultOutcome(Object o)
+    {
+        getFields()[FIELD_DEFAULT_OUTCOME] = o;
+        return this;
+    }
+
+    public Source setOutcomes(Object o)
+    {
+        getFields()[FIELD_OUTCOMES] = o;
+        return this;
+    }
+
+    public Source setCapabilities(Object o)
+    {
+        getFields()[FIELD_CAPABILITIES] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Target.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Target.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Target.java
new file mode 100644
index 0000000..47ccfa0
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/Target.java
@@ -0,0 +1,103 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class Target extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:target:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000029L);
+
+
+    private static final int FIELD_ADDRESS = 0;
+    private static final int FIELD_DURABLE = 1;
+    private static final int FIELD_EXPIRY_POLICY = 2;
+    private static final int FIELD_TIMEOUT = 3;
+    private static final int FIELD_DYNAMIC = 4;
+    private static final int FIELD_DYNAMIC_NODE_PROPERTIES = 5;
+    private static final int FIELD_CAPABILITIES = 6;
+
+    public Target(Object... fields)
+    {
+        super(7);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public Target setAddress(Object o)
+    {
+        getFields()[FIELD_ADDRESS] = o;
+        return this;
+    }
+
+    public Target setDurable(Object o)
+    {
+        getFields()[FIELD_DURABLE] = o;
+        return this;
+    }
+
+    public Target setExpiryPolicy(Object o)
+    {
+        getFields()[FIELD_EXPIRY_POLICY] = o;
+        return this;
+    }
+
+    public Target setTimeout(Object o)
+    {
+        getFields()[FIELD_TIMEOUT] = o;
+        return this;
+    }
+
+    public Target setDynamic(Object o)
+    {
+        getFields()[FIELD_DYNAMIC] = o;
+        return this;
+    }
+
+    public Target setDynamicNodeProperties(Object o)
+    {
+        getFields()[FIELD_DYNAMIC_NODE_PROPERTIES] = o;
+        return this;
+    }
+
+    public Target setCapabilities(Object o)
+    {
+        getFields()[FIELD_CAPABILITIES] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/TransferFrame.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/TransferFrame.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/TransferFrame.java
new file mode 100644
index 0000000..e1f4435
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/TransferFrame.java
@@ -0,0 +1,131 @@
+/*
+ * 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.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class TransferFrame extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:transfer:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000014L);
+
+
+    private static final int FIELD_HANDLE = 0;
+    private static final int FIELD_DELIVERY_ID = 1;
+    private static final int FIELD_DELIVERY_TAG = 2;
+    private static final int FIELD_MESSAGE_FORMAT = 3;
+    private static final int FIELD_SETTLED = 4;
+    private static final int FIELD_MORE = 5;
+    private static final int FIELD_RCV_SETTLE_MODE = 6;
+    private static final int FIELD_STATE = 7;
+    private static final int FIELD_RESUME = 8;
+    private static final int FIELD_ABORTED = 9;
+    private static final int FIELD_BATCHABLE = 10;
+
+    public TransferFrame(Object... fields)
+    {
+        super(11);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public TransferFrame setHandle(Object o)
+    {
+        getFields()[FIELD_HANDLE] = o;
+        return this;
+    }
+
+    public TransferFrame setDeliveryId(Object o)
+    {
+        getFields()[FIELD_DELIVERY_ID] = o;
+        return this;
+    }
+
+    public TransferFrame setDeliveryTag(Object o)
+    {
+        getFields()[FIELD_DELIVERY_TAG] = o;
+        return this;
+    }
+
+    public TransferFrame setMessageFormat(Object o)
+    {
+        getFields()[FIELD_MESSAGE_FORMAT] = o;
+        return this;
+    }
+
+    public TransferFrame setSettled(Object o)
+    {
+        getFields()[FIELD_SETTLED] = o;
+        return this;
+    }
+
+    public TransferFrame setMore(Object o)
+    {
+        getFields()[FIELD_MORE] = o;
+        return this;
+    }
+
+    public TransferFrame setRcvSettleMode(Object o)
+    {
+        getFields()[FIELD_RCV_SETTLE_MODE] = o;
+        return this;
+    }
+
+    public TransferFrame setState(Object o)
+    {
+        getFields()[FIELD_STATE] = o;
+        return this;
+    }
+
+    public TransferFrame setResume(Object o)
+    {
+        getFields()[FIELD_RESUME] = o;
+        return this;
+    }
+
+    public TransferFrame setAborted(Object o)
+    {
+        getFields()[FIELD_ABORTED] = o;
+        return this;
+    }
+
+    public TransferFrame setBatchable(Object o)
+    {
+        getFields()[FIELD_BATCHABLE] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/generate-frames.xsl
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/generate-frames.xsl b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/generate-frames.xsl
new file mode 100644
index 0000000..75e3b65
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/generate-frames.xsl
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
+                xmlns:exsl="http://exslt.org/common"
+                extension-element-prefixes="exsl">
+
+<!-- Used to generate the Java classes in this package.
+     Changes to these classes should be effected by modifying this stylesheet then re-running it,
+     using a stylesheet processor that understands the exsl directives such as xsltproc -->
+
+<xsl:template match="/">
+    <xsl:variable name="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.
+ *
+ */
+</xsl:variable>
+
+    <xsl:for-each select="descendant-or-self::node()[name()='type']">
+
+        <xsl:if test="@provides = 'frame' or @provides = 'sasl-frame'">
+          <xsl:variable name="classname"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>Frame</xsl:variable>
+
+          <xsl:call-template name="typeClass">
+              <xsl:with-param name="license" select="$license"/>
+              <xsl:with-param name="classname" select="$classname"/>
+          </xsl:call-template>
+        </xsl:if>
+
+        <xsl:if test="@provides = 'delivery-state, outcome' or @provides = 'source' or @provides = 'target'">
+          <xsl:variable name="classname"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template></xsl:variable>
+
+          <xsl:call-template name="typeClass">
+              <xsl:with-param name="license" select="$license"/>
+              <xsl:with-param name="classname" select="$classname"/>
+          </xsl:call-template>
+        </xsl:if>
+    </xsl:for-each>
+</xsl:template>
+
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="typeClass">
+    <xsl:param name="license"/>
+    <xsl:param name="classname"/>
+  <exsl:document href="{$classname}.java" method="text">
+  <xsl:value-of select="$license"/>
+package org.apache.qpid.jms.test.testpeer.describedtypes;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-frames.xsl, which resides in this package.
+ */
+public class <xsl:value-of select="$classname"/> extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("<xsl:value-of select="descendant::node()[name()='descriptor']/@name"/>");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(<xsl:value-of select="concat(substring(descendant::node()[name()='descriptor']/@code,1,10),substring(descendant::node()[name()='descriptor']/@code,14))"/>L);
+
+<xsl:for-each select="descendant::node()[name()='field']">
+    private static final int FIELD_<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template> = <xsl:value-of select="count(preceding-sibling::node()[name()='field'])"/>;</xsl:for-each>
+
+    public <xsl:value-of select="$classname"/>(Object... fields)
+    {
+        super(<xsl:value-of select="count(descendant::node()[name()='field'])"/>);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+<xsl:for-each select="descendant::node()[name()='field']">
+    public <xsl:value-of select="$classname"/> set<xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="@name"/></xsl:call-template>(Object o)
+    {
+        getFields()[FIELD_<xsl:call-template name="toUpperDashToUnderscore"><xsl:with-param name="input" select="@name"/></xsl:call-template>] = o;
+        return this;
+    }
+</xsl:for-each>
+}
+
+</exsl:document>
+
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+
+<xsl:template name="constructFromLiteral">
+    <xsl:param name="type"/>
+    <xsl:param name="value"/>
+    <xsl:choose>
+        <xsl:when test="$type = 'string'">"<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'symbol'">Symbol.valueOf("<xsl:value-of select="$value"/>")</xsl:when>
+        <xsl:when test="$type = 'ubyte'">UnsignedByte.valueOf((byte) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ushort'">UnsignedShort.valueOf((short) <xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'uint'">UnsignedInteger.valueOf(<xsl:value-of select="$value"/>)</xsl:when>
+        <xsl:when test="$type = 'ulong'">UnsignedLong.valueOf(<xsl:value-of select="$value"/>L)</xsl:when>
+        <xsl:when test="$type = 'long'"><xsl:value-of select="$value"/>L</xsl:when>
+        <xsl:when test="$type = 'short'">(short)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:when test="$type = 'short'">(byte)<xsl:value-of select="$value"/></xsl:when>
+        <xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
+    </xsl:choose>
+</xsl:template>
+
+<!-- *************************************************************************************************************** -->
+<xsl:template name="substringAfterLast"><xsl:param name="input"/><xsl:param name="arg"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,$arg)"><xsl:call-template name="substringAfterLast"><xsl:with-param name="input"><xsl:value-of select="substring-after($input,$arg)"/></xsl:with-param><xsl:with-param name="arg"><xsl:value-of select="$arg"/></xsl:with-param></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:value-of select="$input"/></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="initCap"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="initLower"><xsl:param name="input"/><xsl:value-of select="translate(substring($input,1,1),'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/><xsl:value-of select="substring($input,2)"/></xsl:template>
+
+    <xsl:template name="toUpper"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:template>
+
+    <xsl:template name="toUpperDashToUnderscore"><xsl:param name="input"/><xsl:value-of select="translate($input,'abcdefghijklmnopqrstuvwxyz-','ABCDEFGHIJKLMNOPQRSTUVWXYZ_')"/></xsl:template>
+
+    <xsl:template name="dashToCamel">
+        <xsl:param name="input"/>
+        <xsl:choose>
+            <xsl:when test="contains($input,'-')"><xsl:call-template name="initCap"><xsl:with-param name="input" select="substring-before($input,'-')"/></xsl:call-template><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="substring-after($input,'-')"/></xsl:call-template></xsl:when>
+            <xsl:otherwise><xsl:call-template name="initCap"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+
+    <xsl:template name="dashToLowerCamel">
+        <xsl:param name="input"/>
+        <xsl:call-template name="initLower"><xsl:with-param name="input"><xsl:call-template name="dashToCamel"><xsl:with-param name="input" select="$input"/></xsl:call-template></xsl:with-param></xsl:call-template>
+    </xsl:template>
+</xsl:stylesheet>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/AmqpValueDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/AmqpValueDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/AmqpValueDescribedType.java
new file mode 100644
index 0000000..d524b46
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/AmqpValueDescribedType.java
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+
+public class AmqpValueDescribedType implements DescribedType
+{
+    private static final Symbol DESCIPTOR_SYMBOL = Symbol.valueOf("amqp:amqp-value:*");
+    private Object _described;
+
+    public AmqpValueDescribedType(Object described)
+    {
+        _described = described;
+    }
+
+    @Override
+    public Object getDescriptor()
+    {
+        return DESCIPTOR_SYMBOL;
+    }
+
+    @Override
+    public Object getDescribed()
+    {
+        return _described;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/ApplicationPropertiesDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/ApplicationPropertiesDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/ApplicationPropertiesDescribedType.java
new file mode 100644
index 0000000..12f92a5
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/ApplicationPropertiesDescribedType.java
@@ -0,0 +1,45 @@
+/*
+ *
+ * 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.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.jms.test.testpeer.MapDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+
+public class ApplicationPropertiesDescribedType extends MapDescribedType
+{
+    private static final Symbol DESCIPTOR_SYMBOL = Symbol.valueOf("amqp:application-properties:map");
+
+    @Override
+    public Object getDescriptor()
+    {
+        return DESCIPTOR_SYMBOL;
+    }
+
+    public void setApplicationProperty(String name, Object value)
+    {
+        if(name == null)
+        {
+            throw new RuntimeException("ApplicationProperties maps must use non-null String keys");
+        }
+
+        getDescribed().put(name, value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/DataDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/DataDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/DataDescribedType.java
new file mode 100644
index 0000000..7205c9f
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/DataDescribedType.java
@@ -0,0 +1,54 @@
+/*
+ *
+ * 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.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+
+public class DataDescribedType implements DescribedType
+{
+    private static final Symbol DESCIPTOR_SYMBOL = Symbol.valueOf("amqp:data:binary");
+    private Binary _described;
+
+    public DataDescribedType(Binary described)
+    {
+        if(described == null)
+        {
+            throw new IllegalArgumentException("provided Binary must not be null");
+        }
+
+        _described = described;
+    }
+
+    @Override
+    public Object getDescriptor()
+    {
+        return DESCIPTOR_SYMBOL;
+    }
+
+    @Override
+    public Object getDescribed()
+    {
+        return _described;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/HeaderDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/HeaderDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/HeaderDescribedType.java
new file mode 100644
index 0000000..ed7cb57
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/HeaderDescribedType.java
@@ -0,0 +1,89 @@
+/*
+ * 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.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-list-sections.xsl, which resides in this package.
+ */
+public class HeaderDescribedType extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:header:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000070L);
+
+
+    private static final int FIELD_DURABLE = 0;
+    private static final int FIELD_PRIORITY = 1;
+    private static final int FIELD_TTL = 2;
+    private static final int FIELD_FIRST_ACQUIRER = 3;
+    private static final int FIELD_DELIVERY_COUNT = 4;
+
+    public HeaderDescribedType(Object... fields)
+    {
+        super(5);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public HeaderDescribedType setDurable(Object o)
+    {
+        getFields()[FIELD_DURABLE] = o;
+        return this;
+    }
+
+    public HeaderDescribedType setPriority(Object o)
+    {
+        getFields()[FIELD_PRIORITY] = o;
+        return this;
+    }
+
+    public HeaderDescribedType setTtl(Object o)
+    {
+        getFields()[FIELD_TTL] = o;
+        return this;
+    }
+
+    public HeaderDescribedType setFirstAcquirer(Object o)
+    {
+        getFields()[FIELD_FIRST_ACQUIRER] = o;
+        return this;
+    }
+
+    public HeaderDescribedType setDeliveryCount(Object o)
+    {
+        getFields()[FIELD_DELIVERY_COUNT] = o;
+        return this;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/MessageAnnotationsDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/MessageAnnotationsDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/MessageAnnotationsDescribedType.java
new file mode 100644
index 0000000..93a45b2
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/MessageAnnotationsDescribedType.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * 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.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.jms.test.testpeer.MapDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+public class MessageAnnotationsDescribedType extends MapDescribedType
+{
+    private static final Symbol DESCIPTOR_SYMBOL = Symbol.valueOf("amqp:message-annotations:map");
+
+    @Override
+    public Object getDescriptor()
+    {
+        return DESCIPTOR_SYMBOL;
+    }
+
+    public void setSymbolKeyedAnnotation(String name, Object value)
+    {
+        getDescribed().put(Symbol.valueOf(name), value);
+    }
+
+    public void setUnsignedLongKeyedAnnotation(UnsignedLong name, Object value)
+    {
+        throw new UnsupportedOperationException("UnsignedLong keys are currently reserved");
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/PropertiesDescribedType.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/PropertiesDescribedType.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/PropertiesDescribedType.java
new file mode 100644
index 0000000..716fc39
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/describedtypes/sections/PropertiesDescribedType.java
@@ -0,0 +1,145 @@
+/*
+ * 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.jms.test.testpeer.describedtypes.sections;
+
+import org.apache.qpid.jms.test.testpeer.ListDescribedType;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+
+/**
+ * Generated by generate-list-sections.xsl, which resides in this package.
+ */
+public class PropertiesDescribedType extends ListDescribedType
+{
+    public static final Symbol DESCRIPTOR_SYMBOL = Symbol.valueOf("amqp:properties:list");
+    public static final UnsignedLong DESCRIPTOR_CODE = UnsignedLong.valueOf(0x0000000000000073L);
+
+
+    private static final int FIELD_MESSAGE_ID = 0;
+    private static final int FIELD_USER_ID = 1;
+    private static final int FIELD_TO = 2;
+    private static final int FIELD_SUBJECT = 3;
+    private static final int FIELD_REPLY_TO = 4;
+    private static final int FIELD_CORRELATION_ID = 5;
+    private static final int FIELD_CONTENT_TYPE = 6;
+    private static final int FIELD_CONTENT_ENCODING = 7;
+    private static final int FIELD_ABSOLUTE_EXPIRY_TIME = 8;
+    private static final int FIELD_CREATION_TIME = 9;
+    private static final int FIELD_GROUP_ID = 10;
+    private static final int FIELD_GROUP_SEQUENCE = 11;
+    private static final int FIELD_REPLY_TO_GROUP_ID = 12;
+
+    public PropertiesDescribedType(Object... fields)
+    {
+        super(13);
+        int i = 0;
+        for(Object field : fields)
+        {
+            getFields()[i++] = field;
+        }
+    }
+
+    @Override
+    public Symbol getDescriptor()
+    {
+        return DESCRIPTOR_SYMBOL;
+    }
+
+    public PropertiesDescribedType setMessageId(Object o)
+    {
+        getFields()[FIELD_MESSAGE_ID] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setUserId(Object o)
+    {
+        getFields()[FIELD_USER_ID] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setTo(Object o)
+    {
+        getFields()[FIELD_TO] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setSubject(Object o)
+    {
+        getFields()[FIELD_SUBJECT] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setReplyTo(Object o)
+    {
+        getFields()[FIELD_REPLY_TO] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setCorrelationId(Object o)
+    {
+        getFields()[FIELD_CORRELATION_ID] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setContentType(Object o)
+    {
+        getFields()[FIELD_CONTENT_TYPE] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setContentEncoding(Object o)
+    {
+        getFields()[FIELD_CONTENT_ENCODING] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setAbsoluteExpiryTime(Object o)
+    {
+        getFields()[FIELD_ABSOLUTE_EXPIRY_TIME] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setCreationTime(Object o)
+    {
+        getFields()[FIELD_CREATION_TIME] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setGroupId(Object o)
+    {
+        getFields()[FIELD_GROUP_ID] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setGroupSequence(Object o)
+    {
+        getFields()[FIELD_GROUP_SEQUENCE] = o;
+        return this;
+    }
+
+    public PropertiesDescribedType setReplyToGroupId(Object o)
+    {
+        getFields()[FIELD_REPLY_TO_GROUP_ID] = o;
+        return this;
+    }
+
+}
+


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


[10/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsStreamMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsStreamMessageTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsStreamMessageTest.java
new file mode 100644
index 0000000..b21068b
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsStreamMessageTest.java
@@ -0,0 +1,1133 @@
+/**
+ * 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.jms.message;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+import javax.jms.StreamMessage;
+
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsStreamMessage;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JmsStreamMessageTest {
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    // ======= general =========
+
+    @Test
+    public void testReadWithEmptyStreamThrowsMEOFE() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+        streamMessage.reset();
+
+        try {
+            streamMessage.readBoolean();
+            fail("Expected exception to be thrown as message has no content");
+        } catch (MessageEOFException meofe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testClearBodyOnNewMessageRemovesExistingValues() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+        streamMessage.writeBoolean(true);
+
+        streamMessage.clearBody();
+
+        streamMessage.writeBoolean(false);
+        streamMessage.reset();
+
+        // check we get only the value added after the clear
+        assertFalse("expected value added after the clear", streamMessage.readBoolean());
+
+        try {
+            streamMessage.readBoolean();
+            fail("Expected exception to be thrown");
+        } catch (MessageEOFException meofe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testNewMessageIsWriteOnlyThrowsMNRE() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        try {
+            streamMessage.readBoolean();
+            fail("Expected exception to be thrown as message is not readable");
+        } catch (MessageNotReadableException mnre) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify the stream position is not incremented during illegal type conversion failure.
+     * This covers every read method except readObject (which doesn't do type conversion) and
+     * readBytes(), which is tested by
+     * {@link #testIllegalTypeConvesionFailureDoesNotIncrementPosition2}
+     *
+     * Write bytes, then deliberately try to retrieve them as illegal types, then check they can
+     * be successfully read.
+     */
+    @Test
+    public void testIllegalTypeConvesionFailureDoesNotIncrementPosition1() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 0, (byte) 255, (byte) 78 };
+
+        streamMessage.writeBytes(bytes);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Long.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, String.class);
+
+        byte[] retrievedByteArray = new byte[bytes.length];
+        int readBytesLength = streamMessage.readBytes(retrievedByteArray);
+
+        assertEquals("Number of bytes read did not match original array length", bytes.length, readBytesLength);
+        assertArrayEquals("Expected array to equal retrieved bytes", bytes, retrievedByteArray);
+        assertEquals("Expected completion return value", -1, streamMessage.readBytes(retrievedByteArray));
+    }
+
+    /**
+     * Verify the stream position is not incremented during illegal type conversion failure.
+     * This test covers only readBytes, other methods are tested by
+     * {@link #testIllegalTypeConvesionFailureDoesNotIncrementPosition1}
+     *
+     * Write String, then deliberately try illegal retrieval as bytes, then check it can be
+     * successfully read.
+     */
+    @Test
+    public void testIllegalTypeConvesionFailureDoesNotIncrementPosition2() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        String stringVal = "myString";
+        streamMessage.writeString(stringVal);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+
+        assertEquals("Expected written string", stringVal, streamMessage.readString());
+    }
+
+    /**
+     * When a null stream entry is encountered, the accessor methods is type dependent and
+     * should either return null, throw NPE, or behave in the same fashion as
+     * <primitive>.valueOf(String).
+     *
+     * Test that this is the case, and in doing show demonstrate that primitive type conversion
+     * failure does not increment the stream position, as shown by not hitting the end of the
+     * stream unexpectedly.
+     */
+    @Test
+    public void testNullStreamEntryResultsInExpectedBehaviour() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        streamMessage.writeObject(null);
+        streamMessage.reset();
+
+        // expect an NFE from the primitive integral <type>.valueOf(null) conversions
+        assertGetStreamEntryThrowsNumberFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsNumberFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsNumberFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsNumberFormatException(streamMessage, Long.class);
+
+        // expect an NPE from the primitive float, double, and char <type>.valuleOf(null)
+        // conversions
+        assertGetStreamEntryThrowsNullPointerException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsNullPointerException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsNullPointerException(streamMessage, Character.class);
+
+        // expect null
+        assertNull(streamMessage.readObject());
+        streamMessage.reset(); // need to reset as read was a success
+        assertNull(streamMessage.readString());
+        streamMessage.reset(); // need to reset as read was a success
+
+        // expect completion value.
+        assertEquals(-1, streamMessage.readBytes(new byte[1]));
+        streamMessage.reset(); // need to reset as read was a success
+
+        // expect false from Boolean.valueOf(null).
+        assertFalse(streamMessage.readBoolean());
+        streamMessage.reset(); // need to reset as read was a success
+    }
+
+
+    @Test
+    public void testClearBodyAppliesCorrectState() throws JMSException {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+        try {
+            streamMessage.writeObject(new Long(2));
+            streamMessage.clearBody();
+            assertFalse(streamMessage.isReadOnlyBody());
+            streamMessage.writeObject(new Long(2));
+            streamMessage.readObject();
+            fail("should throw exception");
+        } catch (MessageNotReadableException mnwe) {
+        } catch (MessageNotWriteableException mnwe) {
+            fail("should be writeable");
+        }
+    }
+
+    @Test
+    public void testResetAppliesCorrectState() throws JMSException {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+        try {
+            streamMessage.writeDouble(24.5);
+            streamMessage.writeLong(311);
+        } catch (MessageNotWriteableException mnwe) {
+            fail("should be writeable");
+        }
+        streamMessage.reset();
+        try {
+            assertTrue(streamMessage.isReadOnlyBody());
+            assertEquals(streamMessage.readDouble(), 24.5, 0);
+            assertEquals(streamMessage.readLong(), 311);
+        } catch (MessageNotReadableException mnre) {
+            fail("should be readable");
+        }
+        try {
+            streamMessage.writeInt(33);
+            fail("should throw exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+    }
+
+    // ======= object =========
+
+    @Test
+    public void testWriteObjectWithIllegalTypeThrowsMFE() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+        try {
+            streamMessage.writeObject(BigInteger.ONE);
+            fail("Expected exception to be thrown");
+        } catch (MessageFormatException mfe) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testWriteReadObject() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        Object nullEntryValue = null;
+        Boolean boolEntryValue = Boolean.valueOf(false);
+        Byte byteEntryValue = Byte.valueOf((byte) 1);
+        Short shortEntryValue = Short.valueOf((short) 2);
+        Integer intEntryValue = Integer.valueOf(3);
+        Long longEntryValue = Long.valueOf(4);
+        Float floatEntryValue = Float.valueOf(5.01F);
+        Double doubleEntryValue = Double.valueOf(6.01);
+        String stringEntryValue = "string";
+        Character charEntryValue = Character.valueOf('c');
+        byte[] bytes = new byte[] { (byte) 1, (byte) 170, (byte) 65 };
+
+        streamMessage.writeObject(nullEntryValue);
+        streamMessage.writeObject(boolEntryValue);
+        streamMessage.writeObject(byteEntryValue);
+        streamMessage.writeObject(shortEntryValue);
+        streamMessage.writeObject(intEntryValue);
+        streamMessage.writeObject(longEntryValue);
+        streamMessage.writeObject(floatEntryValue);
+        streamMessage.writeObject(doubleEntryValue);
+        streamMessage.writeObject(stringEntryValue);
+        streamMessage.writeObject(charEntryValue);
+        streamMessage.writeObject(bytes);
+
+        streamMessage.reset();
+
+        assertEquals("Got unexpected value from stream", nullEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", boolEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", byteEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", shortEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", intEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", longEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", floatEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", doubleEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", stringEntryValue, streamMessage.readObject());
+        assertEquals("Got unexpected value from stream", charEntryValue, streamMessage.readObject());
+        assertArrayEquals("Got unexpected value from stream", bytes, (byte[]) streamMessage.readObject());
+    }
+
+    // ======= bytes =========
+
+    /**
+     * Write bytes, then retrieve them as all of the legal type combinations
+     */
+    @Test
+    public void testWriteBytesReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] value = new byte[] { (byte) 0, (byte) 255, (byte) 78 };
+
+        streamMessage.writeBytes(value);
+        streamMessage.reset();
+
+        byte[] dest = new byte[value.length];
+
+        int readBytesLength = streamMessage.readBytes(dest);
+        assertEquals("Number of bytes read did not match expectation", value.length, readBytesLength);
+        assertArrayEquals("value not as expected", value, dest);
+    }
+
+    /**
+     * Write bytes, then retrieve them as all of the illegal type combinations to verify it
+     * fails as expected
+     */
+    @Test
+    public void testWriteBytesReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] value = new byte[] { (byte) 0, (byte) 255, (byte) 78 };
+
+        streamMessage.writeBytes(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Long.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, String.class);
+    }
+
+    @Test
+    public void testReadBytesWithNullSignalsCompletion() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+        streamMessage.writeObject(null);
+
+        streamMessage.reset();
+
+        assertEquals("Expected immediate completion signal", -1, streamMessage.readBytes(new byte[1]));
+    }
+
+    @Test
+    public void testReadBytesWithZeroLengthSource() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        streamMessage.writeBytes(new byte[0]);
+
+        streamMessage.reset();
+
+        byte[] fullRetrievedBytes = new byte[1];
+
+        assertEquals("Expected no bytes to be read, as none were written", 0, streamMessage.readBytes(fullRetrievedBytes));
+    }
+
+    @Test
+    public void testReadBytesWithZeroLengthDestination() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 11, (byte) 44, (byte) 99 };
+        streamMessage.writeBytes(bytes);
+
+        streamMessage.reset();
+
+        byte[] zeroDestination = new byte[0];
+        byte[] fullRetrievedBytes = new byte[bytes.length];
+
+        assertEquals("Expected no bytes to be read", 0, streamMessage.readBytes(zeroDestination));
+        assertEquals("Expected all bytes to be read", bytes.length, streamMessage.readBytes(fullRetrievedBytes));
+        assertArrayEquals("Expected arrays to be equal", bytes, fullRetrievedBytes);
+        assertEquals("Expected completion signal", -1, streamMessage.readBytes(zeroDestination));
+    }
+
+    @Test
+    public void testReadObjectForBytesReturnsNewArray() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 11, (byte) 44, (byte) 99 };
+        streamMessage.writeBytes(bytes);
+
+        streamMessage.reset();
+
+        byte[] retrievedBytes = (byte[]) streamMessage.readObject();
+
+        assertNotSame("Expected different array objects", bytes, retrievedBytes);
+        assertArrayEquals("Expected arrays to be equal", bytes, retrievedBytes);
+    }
+
+    @Test
+    public void testReadBytesFullWithUndersizedDestinationArrayUsingMultipleReads() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 3, (byte) 78, (byte) 253, (byte) 26, (byte) 8 };
+        assertEquals("bytes should be odd length", 1, bytes.length % 2);
+        int undersizedLength = 2;
+        int remaining = 1;
+
+        streamMessage.writeBytes(bytes);
+        streamMessage.reset();
+
+        byte[] undersizedDestination = new byte[undersizedLength];
+        byte[] fullRetrievedBytes = new byte[bytes.length];
+
+        assertEquals("Number of bytes read did not match destination array length", undersizedLength, streamMessage.readBytes(undersizedDestination));
+        int read = undersizedLength;
+        System.arraycopy(undersizedDestination, 0, fullRetrievedBytes, 0, undersizedLength);
+        assertEquals("Number of bytes read did not match destination array length", undersizedLength, streamMessage.readBytes(undersizedDestination));
+        System.arraycopy(undersizedDestination, 0, fullRetrievedBytes, read, undersizedLength);
+        read += undersizedLength;
+        assertEquals("Number of bytes read did not match expectation", remaining, streamMessage.readBytes(undersizedDestination));
+        System.arraycopy(undersizedDestination, 0, fullRetrievedBytes, read, remaining);
+        read += remaining;
+        assertArrayEquals("Expected array to equal retrieved bytes", bytes, fullRetrievedBytes);
+    }
+
+    @Test
+    public void testReadBytesFullWithPreciselySizedDestinationArray() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 11, (byte) 44, (byte) 99 };
+        streamMessage.writeBytes(bytes);
+
+        streamMessage.reset();
+
+        byte[] retrievedByteArray = new byte[bytes.length];
+        int readBytesLength = streamMessage.readBytes(retrievedByteArray);
+
+        assertEquals("Number of bytes read did not match original array length", bytes.length, readBytesLength);
+        assertArrayEquals("Expected array to equal retrieved bytes", bytes, retrievedByteArray);
+        assertEquals("Expected completion return value", -1, streamMessage.readBytes(retrievedByteArray));
+    }
+
+    @Test
+    public void testReadBytesFullWithOversizedDestinationArray() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 4, (byte) 115, (byte) 255 };
+        streamMessage.writeBytes(bytes);
+
+        streamMessage.reset();
+
+        byte[] oversizedDestination = new byte[bytes.length + 1];
+        int readBytesLength = streamMessage.readBytes(oversizedDestination);
+
+        assertEquals("Number of bytes read did not match original array length", bytes.length, readBytesLength);
+        assertArrayEquals("Expected array subset to equal retrieved bytes", bytes, Arrays.copyOfRange(oversizedDestination, 0, readBytesLength));
+    }
+
+    /**
+     * {@link StreamMessage#readBytes(byte[])} indicates:
+     *
+     * "Once the first readBytes call on a byte[] field value has been made, the full value of
+     * the field must be read before it is valid to read the next field. An attempt to read the
+     * next field before that has been done will throw a MessageFormatException."
+     *
+     * {@link StreamMessage#readObject()} indicates: "An attempt to call readObject to read a
+     * byte field value into a new byte[] object before the full value of the byte field has
+     * been read will throw a MessageFormatException."
+     *
+     * Test that these restrictions are met, and don't interfere with completing the readBytes
+     * usage.
+     */
+    @Test
+    public void testReadObjectAfterPartialReadBytesThrowsMFE() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] bytes = new byte[] { (byte) 11, (byte) 44, (byte) 99 };
+        streamMessage.writeBytes(bytes);
+
+        streamMessage.reset();
+
+        // start reading via readBytes
+        int partialLength = 2;
+        byte[] retrievedByteArray = new byte[partialLength];
+        int readBytesLength = streamMessage.readBytes(retrievedByteArray);
+
+        assertEquals(partialLength, readBytesLength);
+        assertArrayEquals("Expected array subset to equal retrieved bytes", Arrays.copyOf(bytes, partialLength), retrievedByteArray);
+
+        // check that using readObject does not return the full/remaining bytes as a new array
+        try {
+            streamMessage.readObject();
+            fail("expected exception to be thrown");
+        } catch (MessageFormatException mfe) {
+            // expected
+        }
+
+        // finish reading via reaBytes to ensure it can be completed
+        readBytesLength = streamMessage.readBytes(retrievedByteArray);
+        assertEquals(bytes.length - partialLength, readBytesLength);
+        assertArrayEquals("Expected array subset to equal retrieved bytes", Arrays.copyOfRange(bytes, partialLength, bytes.length),
+            Arrays.copyOfRange(retrievedByteArray, 0, readBytesLength));
+    }
+
+    /**
+     * Verify that setting bytes takes a copy of the array. Set bytes subset, then retrieve the
+     * entry and verify the are different arrays and the subsets are equal.
+     */
+    @Test
+    public void testWriteBytesWithOffsetAndLength() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte[] orig = "myBytesAll".getBytes();
+
+        // extract the segment containing 'Bytes'
+        int offset = 2;
+        int length = 5;
+        byte[] segment = Arrays.copyOfRange(orig, offset, offset + length);
+
+        // set the same section from the original bytes
+        streamMessage.writeBytes(orig, offset, length);
+        streamMessage.reset();
+
+        byte[] retrieved = (byte[]) streamMessage.readObject();
+
+        // verify the retrieved bytes from the stream equal the segment but are not the same
+        assertNotSame(orig, retrieved);
+        assertNotSame(segment, retrieved);
+        assertArrayEquals(segment, retrieved);
+    }
+
+    // ========= boolean ========
+
+    @Test
+    public void testWriteReadBoolean() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        boolean value = true;
+
+        streamMessage.writeBoolean(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readBoolean());
+    }
+
+    /**
+     * Set a boolean, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testWriteBooleanReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        boolean value = true;
+
+        streamMessage.writeBoolean(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, value, Boolean.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a boolean, then retrieve it as all of the illegal type combinations to verify it
+     * fails as expected
+     */
+    @Test
+    public void testSetBooleanGetIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        boolean value = true;
+
+        streamMessage.writeBoolean(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Long.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= string ========
+
+    @Test
+    public void testWriteReadString() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        String value = "myString";
+
+        streamMessage.writeString(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readString());
+    }
+
+    /**
+     * Set a string, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testWriteStringReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        String integralValue = String.valueOf(Byte.MAX_VALUE);
+        streamMessage.writeString(integralValue);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(integralValue), String.class);
+        assertGetStreamEntryEquals(streamMessage, true, Boolean.valueOf(integralValue), Boolean.class);
+        assertGetStreamEntryEquals(streamMessage, true, Byte.valueOf(integralValue), Byte.class);
+
+        streamMessage.clearBody();
+        integralValue = String.valueOf(Short.MAX_VALUE);
+        streamMessage.writeString(integralValue);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Short.valueOf(integralValue), Short.class);
+
+        streamMessage.clearBody();
+        integralValue = String.valueOf(Integer.MAX_VALUE);
+        streamMessage.writeString(integralValue);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Integer.valueOf(integralValue), Integer.class);
+
+        streamMessage.clearBody();
+        integralValue = String.valueOf(Long.MAX_VALUE);
+        streamMessage.writeString(integralValue);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Long.valueOf(integralValue), Long.class);
+
+        streamMessage.clearBody();
+        String fpValue = String.valueOf(Float.MAX_VALUE);
+        streamMessage.writeString(fpValue);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Float.valueOf(fpValue), Float.class);
+        assertGetStreamEntryEquals(streamMessage, true, Double.valueOf(fpValue), Double.class);
+    }
+
+    /**
+     * Set a string, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteStringReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        String stringValue = "myString";
+
+        streamMessage.writeString(stringValue);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // TODO - Support Big Strings
+    @Ignore
+    @Test
+    public void testReadBigString() throws JMSException {
+        JmsStreamMessage msg = factory.createStreamMessage();
+        // Test with a 1Meg String
+        StringBuffer bigSB = new StringBuffer(1024 * 1024);
+        for (int i = 0; i < 1024 * 1024; i++) {
+            bigSB.append('a' + i % 26);
+        }
+        String bigString = bigSB.toString();
+
+        msg.writeString(bigString);
+        msg.reset();
+        assertEquals(bigString, msg.readString());
+    }
+
+    // ========= byte ========
+
+    @Test
+    public void testWriteReadByte() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte value = (byte) 6;
+
+        streamMessage.writeByte(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readByte());
+    }
+
+    /**
+     * Set a byte, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testWriteByteReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte value = (byte) 6;
+
+        streamMessage.writeByte(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Byte.valueOf(value), Byte.class);
+        assertGetStreamEntryEquals(streamMessage, true, Short.valueOf(value), Short.class);
+        assertGetStreamEntryEquals(streamMessage, true, Integer.valueOf(value), Integer.class);
+        assertGetStreamEntryEquals(streamMessage, true, Long.valueOf(value), Long.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a byte, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteByteReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        byte value = (byte) 6;
+
+        streamMessage.writeByte(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= short ========
+
+    @Test
+    public void testWriteReadShort() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        short value = (short) 302;
+
+        streamMessage.writeShort(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readShort());
+    }
+
+    /**
+     * Set a short, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testWriteShortReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        short value = (short) 302;
+
+        streamMessage.writeShort(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Short.valueOf(value), Short.class);
+        assertGetStreamEntryEquals(streamMessage, true, Integer.valueOf(value), Integer.class);
+        assertGetStreamEntryEquals(streamMessage, true, Long.valueOf(value), Long.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a short, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteShortReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        short value = (short) 302;
+
+        streamMessage.writeShort(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= char ========
+
+    @Test
+    public void testWriteReadChar() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        char value = 'c';
+
+        streamMessage.writeChar(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readChar());
+    }
+
+    /**
+     * Set a char, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testWriteCharReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        char value = 'c';
+
+        streamMessage.writeChar(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, value, Character.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a char, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteCharReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        char value = 'c';
+
+        streamMessage.writeChar(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Long.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= int ========
+
+    @Test
+    public void testWriteReadInt() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        int value = Integer.MAX_VALUE;
+
+        streamMessage.writeInt(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readInt());
+    }
+
+    /**
+     * Set an int, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testWriteIntReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        int value = Integer.MAX_VALUE;
+
+        streamMessage.writeInt(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Integer.valueOf(value), Integer.class);
+        assertGetStreamEntryEquals(streamMessage, true, Long.valueOf(value), Long.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set an int, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteIntReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        int value = Integer.MAX_VALUE;
+
+        streamMessage.writeInt(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= long ========
+
+    @Test
+    public void testWriteReadLong() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        long value = Long.MAX_VALUE;
+
+        streamMessage.writeLong(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readLong());
+    }
+
+    /**
+     * Set a long, then retrieve it as all of the legal type combinations to verify it is parsed
+     * correctly
+     */
+    @Test
+    public void testWriteLongReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        long value = Long.MAX_VALUE;
+
+        streamMessage.writeLong(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Long.valueOf(value), Long.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a long, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteLongReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        long value = Long.MAX_VALUE;
+
+        streamMessage.writeLong(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Double.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= float ========
+
+    @Test
+    public void testWriteReadFloat() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        float value = Float.MAX_VALUE;
+
+        streamMessage.writeFloat(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readFloat(), 0.0);
+    }
+
+    /**
+     * Set a float, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testWriteFloatReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        float value = Float.MAX_VALUE;
+
+        streamMessage.writeFloat(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Float.valueOf(value), Float.class);
+        assertGetStreamEntryEquals(streamMessage, true, Double.valueOf(value), Double.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a float, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteFloatReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        float value = Float.MAX_VALUE;
+
+        streamMessage.writeFloat(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Long.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= double ========
+
+    @Test
+    public void testWriteReadDouble() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        double value = Double.MAX_VALUE;
+
+        streamMessage.writeDouble(value);
+        streamMessage.reset();
+
+        assertEquals("Value not as expected", value, streamMessage.readDouble(), 0.0);
+    }
+
+    /**
+     * Set a double, then retrieve it as all of the legal type combinations to verify it is
+     * parsed correctly
+     */
+    @Test
+    public void testWriteDoubleReadLegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        double value = Double.MAX_VALUE;
+
+        streamMessage.writeDouble(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryEquals(streamMessage, true, Double.valueOf(value), Double.class);
+        assertGetStreamEntryEquals(streamMessage, true, String.valueOf(value), String.class);
+    }
+
+    /**
+     * Set a double, then retrieve it as all of the illegal type combinations to verify it fails
+     * as expected
+     */
+    @Test
+    public void testWriteDoubleReadIllegal() throws Exception {
+        JmsStreamMessage streamMessage = factory.createStreamMessage();
+
+        double value = Double.MAX_VALUE;
+
+        streamMessage.writeDouble(value);
+        streamMessage.reset();
+
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Boolean.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Byte.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Short.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Character.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Integer.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Long.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, Float.class);
+        assertGetStreamEntryThrowsMessageFormatException(streamMessage, byte[].class);
+    }
+
+    // ========= utility methods ========
+
+    private void assertGetStreamEntryEquals(JmsStreamMessage testMessage, boolean resetStreamAfter, Object expectedValue, Class<?> clazz) throws JMSException {
+        if (clazz == byte[].class) {
+            throw new IllegalArgumentException("byte[] values not suported");
+        }
+
+        Object actualValue = getStreamEntryUsingTypeMethod(testMessage, clazz, null);
+        assertEquals(expectedValue, actualValue);
+
+        if (resetStreamAfter) {
+            testMessage.reset();
+        }
+    }
+
+    private void assertGetStreamEntryThrowsMessageFormatException(JmsStreamMessage testMessage, Class<?> clazz) throws JMSException {
+        try {
+            getStreamEntryUsingTypeMethod(testMessage, clazz, new byte[0]);
+
+            fail("expected exception to be thrown");
+        } catch (MessageFormatException jmsMFE) {
+            // expected
+        }
+    }
+
+    private void assertGetStreamEntryThrowsNullPointerException(JmsStreamMessage testMessage, Class<?> clazz) throws JMSException {
+        try {
+            getStreamEntryUsingTypeMethod(testMessage, clazz, new byte[0]);
+
+            fail("expected exception to be thrown");
+        } catch (NullPointerException npe) {
+            // expected
+        }
+    }
+
+    private void assertGetStreamEntryThrowsNumberFormatException(JmsStreamMessage testMessage, Class<?> clazz) throws JMSException {
+        assertGetStreamEntryThrowsNumberFormatException(testMessage, clazz, null);
+    }
+
+    private void assertGetStreamEntryThrowsNumberFormatException(JmsStreamMessage testMessage, Class<?> clazz, byte[] destination) throws JMSException {
+        if (clazz == byte[].class && destination == null) {
+            throw new IllegalArgumentException("Destinatinon byte[] must be supplied");
+        }
+
+        try {
+            getStreamEntryUsingTypeMethod(testMessage, clazz, destination);
+
+            fail("expected exception to be thrown");
+        } catch (NumberFormatException nfe) {
+            // expected
+        }
+    }
+
+    private Object getStreamEntryUsingTypeMethod(JmsStreamMessage testMessage, Class<?> clazz, byte[] destination) throws JMSException {
+        if (clazz == Boolean.class) {
+            return testMessage.readBoolean();
+        } else if (clazz == Byte.class) {
+            return testMessage.readByte();
+        } else if (clazz == Character.class) {
+            return testMessage.readChar();
+        } else if (clazz == Short.class) {
+            return testMessage.readShort();
+        } else if (clazz == Integer.class) {
+            return testMessage.readInt();
+        } else if (clazz == Long.class) {
+            return testMessage.readLong();
+        } else if (clazz == Float.class) {
+            return testMessage.readFloat();
+        } else if (clazz == Double.class) {
+            return testMessage.readDouble();
+        } else if (clazz == String.class) {
+            return testMessage.readString();
+        } else if (clazz == byte[].class) {
+            return testMessage.readBytes(destination);
+        } else {
+            throw new RuntimeException("Unexpected entry type class");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsTextMessageTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsTextMessageTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsTextMessageTest.java
new file mode 100644
index 0000000..6757ab8
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/message/JmsTextMessageTest.java
@@ -0,0 +1,138 @@
+/**
+ * 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.jms.message;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+
+import javax.jms.JMSException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.message.JmsDefaultMessageFactory;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsTextMessage;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JmsTextMessageTest {
+
+    private final JmsMessageFactory factory = new JmsDefaultMessageFactory();
+
+    @Test
+    public void testShallowCopy() throws JMSException {
+        JmsTextMessage msg = factory.createTextMessage();
+        String string = "str";
+        msg.setText(string);
+        JmsTextMessage copy = msg.copy();
+        assertTrue(msg.getText() == copy.getText());
+    }
+
+    @Test
+    public void testSetText() throws JMSException {
+        JmsTextMessage msg = factory.createTextMessage();
+        String str = "testText";
+        msg.setText(str);
+        assertEquals(msg.getText(), str);
+    }
+
+    @Test
+    public void testClearBody() throws JMSException, IOException {
+        JmsTextMessage textMessage = factory.createTextMessage();
+        textMessage.setText("string");
+        textMessage.clearBody();
+        assertFalse(textMessage.isReadOnlyBody());
+        assertNull(textMessage.getText());
+        try {
+            textMessage.setText("String");
+            textMessage.getText();
+        } catch (MessageNotWriteableException mnwe) {
+            fail("should be writeable");
+        } catch (MessageNotReadableException mnre) {
+            fail("should be readable");
+        }
+    }
+
+    @Test
+    public void testReadOnlyBody() throws JMSException {
+        JmsTextMessage textMessage = factory.createTextMessage();
+        textMessage.setText("test");
+        textMessage.setReadOnlyBody(true);
+        try {
+            textMessage.getText();
+        } catch (MessageNotReadableException e) {
+            fail("should be readable");
+        }
+        try {
+            textMessage.setText("test");
+            fail("should throw exception");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+    }
+
+    @Test
+    public void testWriteOnlyBody() throws JMSException { // should always be readable
+        JmsTextMessage textMessage = factory.createTextMessage();
+        textMessage.setReadOnlyBody(false);
+        try {
+            textMessage.setText("test");
+            textMessage.getText();
+        } catch (MessageNotReadableException e) {
+            fail("should be readable");
+        }
+        textMessage.setReadOnlyBody(true);
+        try {
+            textMessage.getText();
+            textMessage.setText("test");
+            fail("should throw exception");
+        } catch (MessageNotReadableException e) {
+            fail("should be readable");
+        } catch (MessageNotWriteableException mnwe) {
+        }
+    }
+
+    // TODO - Fix toString and null body.
+    @Test
+    public void testShortText() throws Exception {
+        String shortText = "Content";
+        JmsTextMessage shortMessage = factory.createTextMessage();
+        shortMessage.setText(shortText);
+        //assertTrue(shortMessage.toString().contains("text = " + shortText));
+        assertTrue(shortMessage.getText().equals(shortText));
+
+        String longText = "Very very very very veeeeeeery loooooooooooooooooooooooooooooooooong text";
+        // String longExpectedText = "Very very very very veeeeeeery looooooooooooo...ooooong text";
+        JmsTextMessage longMessage = factory.createTextMessage();
+        longMessage.setText(longText);
+        //assertTrue(longMessage.toString().contains("text = " + longExpectedText));
+        assertTrue(longMessage.getText().equals(longText));
+    }
+
+    @Test
+    public void testNullText() throws Exception {
+        JmsTextMessage nullMessage = factory.createTextMessage();
+        nullMessage.setText(null);
+        assertNull(nullMessage.getText());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelperTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelperTest.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelperTest.java
new file mode 100644
index 0000000..b168ec6
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelperTest.java
@@ -0,0 +1,496 @@
+/*
+ *
+ * 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.jms.provider.amqp.message;
+
+import static org.junit.Assert.*;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import org.apache.qpid.jms.exceptions.IdConversionException;
+import org.apache.qpid.jms.provider.amqp.message.AmqpMessageIdHelper;
+import org.apache.qpid.jms.test.QpidJmsTestCase;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AmqpMessageIdHelperTest extends QpidJmsTestCase {
+    private AmqpMessageIdHelper _messageIdHelper;
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        _messageIdHelper = new AmqpMessageIdHelper();
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#hasMessageIdPrefix(String)} returns true for strings that begin "ID:"
+     */
+    @Test
+    public void testHasIdPrefixWithPrefix() {
+        String myId = "ID:something";
+        assertTrue("'ID:' prefix should have been identified", _messageIdHelper.hasMessageIdPrefix(myId));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#hasMessageIdPrefix(String)} returns false for string beings "ID" without colon.
+     */
+    @Test
+    public void testHasIdPrefixWithIDButNoColonPrefix() {
+        String myIdNoColon = "IDsomething";
+        assertFalse("'ID' prefix should not have been identified without trailing colon", _messageIdHelper.hasMessageIdPrefix(myIdNoColon));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#hasMessageIdPrefix(String)} returns false for null
+     */
+    @Test
+    public void testHasIdPrefixWithNull() {
+        String nullString = null;
+        assertFalse("null string should not result in identification as having the prefix", _messageIdHelper.hasMessageIdPrefix(nullString));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#hasMessageIdPrefix(String)} returns false for strings that doesnt have "ID:" anywhere
+     */
+    @Test
+    public void testHasIdPrefixWithoutPrefix() {
+        String myNonId = "something";
+        assertFalse("string without 'ID:' anywhere should not have been identified as having the prefix", _messageIdHelper.hasMessageIdPrefix(myNonId));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#hasMessageIdPrefix(String)} returns false for strings has lowercase "id:" prefix
+     */
+    @Test
+    public void testHasIdPrefixWithLowercaseID() {
+        String myLowerCaseNonId = "id:something";
+        assertFalse("lowercase 'id:' prefix should not result in identification as having 'ID:' prefix", _messageIdHelper.hasMessageIdPrefix(myLowerCaseNonId));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#stripMessageIdPrefix(String)} strips "ID:" from strings that do begin "ID:"
+     */
+    @Test
+    public void testStripMessageIdPrefixWithPrefix() {
+        String myIdWithoutPrefix = "something";
+        String myId = "ID:" + myIdWithoutPrefix;
+        assertEquals("'ID:' prefix should have been stripped", myIdWithoutPrefix, _messageIdHelper.stripMessageIdPrefix(myId));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#stripMessageIdPrefix(String)} only strips one "ID:" from strings that
+     * begin "ID:ID:...."
+     */
+    @Test
+    public void testStripMessageIdPrefixWithDoublePrefix() {
+        String myIdWithSinglePrefix = "ID:something";
+        String myIdWithDoublePrefix = "ID:" + myIdWithSinglePrefix;
+        assertEquals("'ID:' prefix should only have been stripped once", myIdWithSinglePrefix, _messageIdHelper.stripMessageIdPrefix(myIdWithDoublePrefix));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#stripMessageIdPrefix(String)} does not alter strings that begins "ID" without a colon.
+     */
+    @Test
+    public void testStripMessageIdPrefixWithIDButNoColonPrefix() {
+        String myIdNoColon = "IDsomething";
+        assertEquals("string without 'ID:' prefix should have been returned unchanged", myIdNoColon, _messageIdHelper.stripMessageIdPrefix(myIdNoColon));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#stripMessageIdPrefix(String)} returns null if given null;
+     */
+    @Test
+    public void testStripMessageIdPrefixWithNull() {
+        String nullString = null;
+        assertNull("null string should have been returned", _messageIdHelper.stripMessageIdPrefix(nullString));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#stripMessageIdPrefix(String)} does not alter string that doesn't begin "ID:"
+     */
+    @Test
+    public void testStripMessageIdPrefixWithoutIDAnywhere() {
+        String myNonId = "something";
+        assertEquals("string without 'ID:' anywhere should have been returned unchanged", myNonId, _messageIdHelper.stripMessageIdPrefix(myNonId));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#stripMessageIdPrefix(String)} does not alter string with lowercase "id:"
+     */
+    @Test
+    public void testStripMessageIdPrefixWithLowercaseID() {
+        String myLowerCaseNonId = "id:something";
+        assertEquals("string with lowercase 'id:' prefix should have been returned unchanged", myLowerCaseNonId, _messageIdHelper.stripMessageIdPrefix(myLowerCaseNonId));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns null if given null
+     */
+    @Test
+    public void testToBaseMessageIdStringWithNull() {
+        String nullString = null;
+        assertNull("null string should have been returned", _messageIdHelper.toBaseMessageIdString(nullString));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} throws an IAE if given an unexpected object type.
+     */
+    @Test
+    public void testToBaseMessageIdStringThrowsIAEWithUnexpectedType() {
+        try {
+            _messageIdHelper.toBaseMessageIdString(new Object());
+            fail("expected exception not thrown");
+        } catch (IllegalArgumentException iae) {
+            // expected
+        }
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns the given
+     * basic string unchanged
+     */
+    @Test
+    public void testToBaseMessageIdStringWithString() {
+        String stringMessageId = "myIdString";
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(stringMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", stringMessageId, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded string, when the given string happens to already begin with
+     * the {@link AmqpMessageIdHelper#AMQP_UUID_PREFIX}.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForUUID() {
+        String uuidStringMessageId = AmqpMessageIdHelper.AMQP_UUID_PREFIX + UUID.randomUUID();
+        String expected = AmqpMessageIdHelper.AMQP_STRING_PREFIX + uuidStringMessageId;
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(uuidStringMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded string, when the given string happens to already begin with
+     * the {@link AmqpMessageIdHelper#AMQP_ULONG_PREFIX}.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForLong() {
+        String longStringMessageId = AmqpMessageIdHelper.AMQP_ULONG_PREFIX + Long.valueOf(123456789L);
+        String expected = AmqpMessageIdHelper.AMQP_STRING_PREFIX + longStringMessageId;
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(longStringMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded string, when the given string happens to already begin with
+     * the {@link AmqpMessageIdHelper#AMQP_BINARY_PREFIX}.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForBinary() {
+        String binaryStringMessageId = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + "0123456789ABCDEF";
+        String expected = AmqpMessageIdHelper.AMQP_STRING_PREFIX + binaryStringMessageId;
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(binaryStringMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded string (effectively twice), when the given string happens to already begin with
+     * the {@link AmqpMessageIdHelper#AMQP_STRING_PREFIX}.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithStringBeginningWithEncodingPrefixForString() {
+        String stringMessageId = AmqpMessageIdHelper.AMQP_STRING_PREFIX + "myStringId";
+        String expected = AmqpMessageIdHelper.AMQP_STRING_PREFIX + stringMessageId;
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(stringMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded UUID when given a UUID object.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithUUID() {
+        UUID uuidMessageId = UUID.randomUUID();
+        String expected = AmqpMessageIdHelper.AMQP_UUID_PREFIX + uuidMessageId.toString();
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(uuidMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded ulong when given a Long object.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithLong() {
+        Long longMessageId = Long.valueOf(123456789L);
+        String expected = AmqpMessageIdHelper.AMQP_ULONG_PREFIX + longMessageId.toString();
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(longMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded ulong when given a BigInteger object.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithBigInteger() {
+        BigInteger bigIntMessageId = BigInteger.valueOf(123456789L);
+        String expected = AmqpMessageIdHelper.AMQP_ULONG_PREFIX + bigIntMessageId.toString();
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(bigIntMessageId);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toBaseMessageIdString(String)} returns a string
+     * indicating an AMQP encoded binary when given a ByteBuffer object.
+     */
+    @Test
+    public void testToBaseMessageIdStringWithByteBufferBinary() {
+        byte[] bytes = new byte[] { (byte) 0x00, (byte) 0xAB, (byte) 0x09, (byte) 0xFF };
+        ByteBuffer buf = ByteBuffer.wrap(bytes);
+
+        String expected = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + "00AB09FF";
+
+        String baseMessageIdString = _messageIdHelper.toBaseMessageIdString(buf);
+        assertNotNull("null string should not have been returned", baseMessageIdString);
+        assertEquals("expected base id string was not returned", expected, baseMessageIdString);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns a ulong
+     * (represented as a BigInteger) when given a string indicating an
+     * encoded AMQP ulong id.
+     */
+    @Test
+    public void testToIdObjectWithEncodedUlong() throws Exception {
+        BigInteger longId = BigInteger.valueOf(123456789L);
+        String provided = AmqpMessageIdHelper.AMQP_ULONG_PREFIX + "123456789";
+
+        Object idObject = _messageIdHelper.toIdObject(provided);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", longId, idObject);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns binary
+     * (represented as a ByteBuffer) when given a string indicating an
+     * encoded AMQP binary id, using upper case hex characters
+     */
+    @Test
+    public void testToIdObjectWithEncodedBinaryUppercaseHexString() throws Exception {
+        byte[] bytes = new byte[] { (byte) 0x00, (byte) 0xAB, (byte) 0x09, (byte) 0xFF };
+        ByteBuffer binaryId = ByteBuffer.wrap(bytes);
+
+        String provided = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + "00AB09FF";
+
+        Object idObject = _messageIdHelper.toIdObject(provided);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", binaryId, idObject);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns null
+     * when given null.
+     */
+    @Test
+    public void testToIdObjectWithNull() throws Exception {
+        assertNull("null object should have been returned", _messageIdHelper.toIdObject(null));
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns binary
+     * (represented as a ByteBuffer) when given a string indicating an
+     * encoded AMQP binary id, using lower case hex characters.
+     */
+    @Test
+    public void testToIdObjectWithEncodedBinaryLowercaseHexString() throws Exception {
+        byte[] bytes = new byte[] { (byte) 0x00, (byte) 0xAB, (byte) 0x09, (byte) 0xFF };
+        ByteBuffer binaryId = ByteBuffer.wrap(bytes);
+
+        String provided = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + "00ab09ff";
+
+        Object idObject = _messageIdHelper.toIdObject(provided);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", binaryId, idObject);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns a UUID
+     * when given a string indicating an encoded AMQP uuid id.
+     */
+    @Test
+    public void testToIdObjectWithEncodedUuid() throws Exception {
+        UUID uuid = UUID.randomUUID();
+        String provided = AmqpMessageIdHelper.AMQP_UUID_PREFIX + uuid.toString();
+
+        Object idObject = _messageIdHelper.toIdObject(provided);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", uuid, idObject);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns a string
+     * when given a string without any type encoding prefix.
+     */
+    @Test
+    public void testToIdObjectWithStringContainingNoEncodingPrefix() throws Exception {
+        String stringId = "myStringId";
+
+        Object idObject = _messageIdHelper.toIdObject(stringId);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", stringId, idObject);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} returns the remainder of the
+     * provided string after removing the {@link AmqpMessageIdHelper#AMQP_STRING_PREFIX} prefix.
+     */
+    @Test
+    public void testToIdObjectWithStringContainingStringEncodingPrefix() throws Exception {
+        String suffix = "myStringSuffix";
+        String stringId = AmqpMessageIdHelper.AMQP_STRING_PREFIX + suffix;
+
+        Object idObject = _messageIdHelper.toIdObject(stringId);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", suffix, idObject);
+    }
+
+    /**
+     * Test that when given a string with with the {@link AmqpMessageIdHelper#AMQP_STRING_PREFIX} prefix
+     * and then additionally the {@link AmqpMessageIdHelper#AMQP_UUID_PREFIX}, the
+     * {@link AmqpMessageIdHelper#toIdObject(String)} method returns the remainder of the provided string
+     *  after removing the {@link AmqpMessageIdHelper#AMQP_STRING_PREFIX} prefix.
+     */
+    @Test
+    public void testToIdObjectWithStringContainingStringEncodingPrefixAndThenUuidPrefix() throws Exception {
+        String encodedUuidString = AmqpMessageIdHelper.AMQP_UUID_PREFIX + UUID.randomUUID().toString();
+        String stringId = AmqpMessageIdHelper.AMQP_STRING_PREFIX + encodedUuidString;
+
+        Object idObject = _messageIdHelper.toIdObject(stringId);
+        assertNotNull("null object should not have been returned", idObject);
+        assertEquals("expected id object was not returned", encodedUuidString, idObject);
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} throws an
+     * {@link IdConversionException} when presented with an encoded binary hex string
+     * of uneven length (after the prefix) that thus can't be converted due to each
+     * byte using 2 characters
+     */
+    @Test
+    public void testToIdObjectWithStringContainingBinaryHexThrowsICEWithUnevenLengthString() {
+        String unevenHead = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + "123";
+
+        try {
+            _messageIdHelper.toIdObject(unevenHead);
+            fail("expected exception was not thrown");
+        } catch (IdConversionException iae) {
+            // expected
+            String msg = iae.getCause().getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("even length"));
+        }
+    }
+
+    /**
+     * Test that {@link AmqpMessageIdHelper#toIdObject(String)} throws an
+     * {@link IdConversionException} when presented with an encoded binary hex
+     * string (after the prefix) that contains characters other than 0-9
+     * and A-F and a-f, and thus can't be converted
+     */
+    @Test
+    public void testToIdObjectWithStringContainingBinaryHexThrowsICEWithNonHexCharacters() {
+
+        // char before '0'
+        char nonHexChar = '/';
+        String nonHexString = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        } catch (IdConversionException ice) {
+            // expected
+            String msg = ice.getCause().getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+
+        // char after '9', before 'A'
+        nonHexChar = ':';
+        nonHexString = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        } catch (IdConversionException ice) {
+            // expected
+            String msg = ice.getCause().getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+
+        // char after 'F', before 'a'
+        nonHexChar = 'G';
+        nonHexString = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        } catch (IdConversionException ice) {
+            // expected
+            String msg = ice.getCause().getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+
+        // char after 'f'
+        nonHexChar = 'g';
+        nonHexString = AmqpMessageIdHelper.AMQP_BINARY_PREFIX + nonHexChar + nonHexChar;
+
+        try {
+            _messageIdHelper.toIdObject(nonHexString);
+            fail("expected exception was not thrown");
+        } catch (IdConversionException ice) {
+            // expected
+            String msg = ice.getCause().getMessage();
+            assertTrue("Message was not as expected: " + msg, msg.contains("non-hex"));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/QpidJmsTestCase.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/QpidJmsTestCase.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/QpidJmsTestCase.java
new file mode 100644
index 0000000..414e98d
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/QpidJmsTestCase.java
@@ -0,0 +1,98 @@
+/*
+ * 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.jms.test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class QpidJmsTestCase {
+    private final Logger _logger = LoggerFactory.getLogger(getClass());
+
+    private final Map<String, String> _propertiesSetForTest = new HashMap<String, String>();
+
+    @Rule
+    public TestName _testName = new TestName();
+
+    /**
+     * Set a System property for duration of this test only. The tearDown will guarantee to reset the property to its
+     * previous value after the test completes.
+     *
+     * @param property
+     *            The property to set
+     * @param value
+     *            the value to set it to, if null, the property will be cleared
+     */
+    protected void setTestSystemProperty(final String property, final String value) {
+        if (!_propertiesSetForTest.containsKey(property)) {
+            // Record the current value so we can revert it later.
+            _propertiesSetForTest.put(property, System.getProperty(property));
+        }
+
+        if (value == null) {
+            System.clearProperty(property);
+            _logger.info("Set system property '" + property + "' to be cleared");
+        } else {
+            System.setProperty(property, value);
+            _logger.info("Set system property '" + property + "' to: '" + value + "'");
+        }
+
+    }
+
+    /**
+     * Restore the System property values that were set by this test run.
+     */
+    protected void revertTestSystemProperties() {
+        if (!_propertiesSetForTest.isEmpty()) {
+            for (String key : _propertiesSetForTest.keySet()) {
+                String value = _propertiesSetForTest.get(key);
+                if (value != null) {
+                    System.setProperty(key, value);
+                    _logger.info("Reverted system property '" + key + "' to: '" + value + "'");
+                } else {
+                    System.clearProperty(key);
+                    _logger.info("Reverted system property '" + key + "' to be cleared");
+                }
+            }
+
+            _propertiesSetForTest.clear();
+        }
+    }
+
+    @After
+    public void tearDown() throws java.lang.Exception {
+        _logger.info("========== tearDown " + getTestName() + " ==========");
+        revertTestSystemProperties();
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        _logger.info("========== start " + getTestName() + " ==========");
+    }
+
+    protected String getTestName() {
+        return getClass().getSimpleName() + "." + _testName.getMethodName();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AbstractFrameFieldAndPayloadMatchingHandler.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AbstractFrameFieldAndPayloadMatchingHandler.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AbstractFrameFieldAndPayloadMatchingHandler.java
new file mode 100644
index 0000000..e835af3
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AbstractFrameFieldAndPayloadMatchingHandler.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.jms.test.testpeer;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.hamcrest.Matcher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractFrameFieldAndPayloadMatchingHandler extends FrameMatchingHandler
+{
+    private final Logger _logger = LoggerFactory.getLogger(getClass());
+
+    private final Map<Enum<?>, Matcher<?>> _fieldMatchers;
+    private Map<Enum<?>, Object> _receivedFields;
+
+    /**
+     * @param fieldMatchers a map of field matchers, keyed by enums representing the fields
+     * (the enums just need to have an ordinal number matching the AMQP spec field order,
+     * and preferably a sensible name)
+     */
+    protected AbstractFrameFieldAndPayloadMatchingHandler(FrameType frameType,
+                                                int channel,
+                                                UnsignedLong numericDescriptor,
+                                                Symbol symbolicDescriptor,
+                                                Map<Enum<?>, Matcher<?>> fieldMatchers,
+                                                Runnable onSuccess)
+    {
+        super(frameType, channel, numericDescriptor, symbolicDescriptor, onSuccess);
+        _fieldMatchers = fieldMatchers;
+    }
+
+    protected Map<Enum<?>, Matcher<?>> getMatchers()
+    {
+        return _fieldMatchers;
+    }
+
+    /**
+     * Returns the received values, keyed by enums representing the fields
+     * (the enums have an ordinal number matching the AMQP spec field order,
+     * and a sensible name)
+     */
+    @Override
+    protected Map<Enum<?>, Object> getReceivedFields()
+    {
+        return _receivedFields;
+    }
+
+    @Override
+    protected void verifyFrame(List<Object> described, Binary payload)
+    {
+        verifyFields(described);
+        verifyPayload(payload);
+    }
+
+    protected void verifyFields(List<Object> described)
+    {
+        int fieldNumber = 0;
+        HashMap<Enum<?>, Object> valueMap = new HashMap<>();
+        for(Object value : described)
+        {
+            valueMap.put(getField(fieldNumber++), value);
+        }
+
+        _receivedFields = valueMap;
+
+        _logger.debug("About to check the fields of the described type."
+                + "\n  Received:" + valueMap
+                + "\n  Expectations: " + _fieldMatchers);
+        for(Map.Entry<Enum<?>, Matcher<?>> entry : _fieldMatchers.entrySet())
+        {
+            @SuppressWarnings("unchecked")
+            Matcher<Object> matcher = (Matcher<Object>) entry.getValue();
+            Enum<?> field = entry.getKey();
+            assertThat("Field " + field + " value should match", valueMap.get(field), matcher);
+        }
+    }
+
+    /**
+     * Intended to be overridden in most cases (but not necessarily all - hence not marked as abstract)
+     */
+    protected Enum<?> getField(int fieldIndex)
+    {
+        throw new UnsupportedOperationException("getFieldName is expected to be overridden by subclass if it is required");
+    }
+
+    protected abstract void verifyPayload(Binary payload);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpDataFramer.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpDataFramer.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpDataFramer.java
new file mode 100644
index 0000000..0fb3d42
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpDataFramer.java
@@ -0,0 +1,64 @@
+/*
+ * 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.jms.test.testpeer;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.DescribedType;
+import org.apache.qpid.proton.codec.Data;
+
+/**
+ * Generates frames as per section 2.3.1 of the AMQP spec
+ */
+public class AmqpDataFramer
+{
+    private static final int CAPACITY = 2024;
+    private static final byte FRAME_PREAMBLE_SIZE_IN_FOUR_BYTE_WORDS = 2;
+
+    public static byte[] encodeFrame(FrameType type, int channel, DescribedType describedType, Binary payload)
+    {
+        ByteBuffer buffer = ByteBuffer.allocate(CAPACITY);  //TODO: set a proper size
+
+        buffer.position(8); // leave hole for frame header
+
+        Data frameBody = Proton.data(CAPACITY);
+        frameBody.putDescribedType(describedType);
+        frameBody.encode(buffer);
+        if(payload != null)
+        {
+            buffer.put(payload.asByteBuffer());
+        }
+
+        int frameSize = buffer.position();
+        buffer.rewind();
+        buffer.putInt(frameSize);
+        buffer.put(FRAME_PREAMBLE_SIZE_IN_FOUR_BYTE_WORDS);
+        buffer.put((byte)type.ordinal());
+        buffer.putShort((short)channel);
+
+        byte[] target = new byte[frameSize];
+
+        buffer.rewind();
+        buffer.get(target, 0, frameSize);
+        return target;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpPeerRunnable.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpPeerRunnable.java b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpPeerRunnable.java
new file mode 100644
index 0000000..55b6df7
--- /dev/null
+++ b/qpid-jms-client/src/test/java/org/apache/qpid/jms/test/testpeer/AmqpPeerRunnable.java
@@ -0,0 +1,25 @@
+/*
+ *
+ * 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.jms.test.testpeer;
+
+public interface AmqpPeerRunnable extends Runnable
+{
+}


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


[02/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/FailoverProviderTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/FailoverProviderTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/FailoverProviderTest.java
new file mode 100644
index 0000000..a458ab7
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/FailoverProviderTest.java
@@ -0,0 +1,92 @@
+/**
+ * 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.jms.failover;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.qpid.jms.provider.DefaultProviderListener;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.provider.failover.FailoverProvider;
+import org.apache.qpid.jms.provider.failover.FailoverProviderFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test basic functionality of the FailoverProvider class.
+ */
+public class FailoverProviderTest extends AmqpTestSupport {
+
+    @Test(timeout=60000)
+    public void testFailoverCreate() throws Exception {
+        URI brokerURI = new URI("failover:" + getBrokerAmqpConnectionURI());
+        Provider asyncProvider = FailoverProviderFactory.createAsync(brokerURI);
+        assertNotNull(asyncProvider);
+        FailoverProvider provider = (FailoverProvider) asyncProvider;
+        assertNotNull(provider);
+    }
+
+    @Test(timeout=60000)
+    public void testFailoverURIConfiguration() throws Exception {
+        URI brokerURI = new URI("failover://(" + getBrokerAmqpConnectionURI() + ")" +
+                                "?maxReconnectDelay=1000&useExponentialBackOff=false" +
+                                "&maxReconnectAttempts=10&startupMaxReconnectAttempts=20");
+        Provider asyncProvider = FailoverProviderFactory.createAsync(brokerURI);
+        assertNotNull(asyncProvider);
+        FailoverProvider provider = (FailoverProvider) asyncProvider;
+        assertNotNull(provider);
+
+        assertEquals(1000, provider.getMaxReconnectDelay());
+        assertFalse(provider.isUseExponentialBackOff());
+        assertEquals(10, provider.getMaxReconnectAttempts());
+        assertEquals(20, provider.getStartupMaxReconnectAttempts());
+    }
+
+    @Test(timeout=60000)
+    public void testStartupReconnectAttempts() throws Exception {
+        URI brokerURI = new URI("failover://(amqp://localhost:61616)" +
+                                "?maxReconnectDelay=100&startupMaxReconnectAttempts=5");
+        Provider asyncProvider = FailoverProviderFactory.createAsync(brokerURI);
+        assertNotNull(asyncProvider);
+        FailoverProvider provider = (FailoverProvider) asyncProvider;
+        assertNotNull(provider);
+
+        assertEquals(100, provider.getMaxReconnectDelay());
+        assertEquals(5, provider.getStartupMaxReconnectAttempts());
+
+        final CountDownLatch failed = new CountDownLatch(1);
+
+        provider.setProviderListener(new DefaultProviderListener() {
+
+            @Override
+            public void onConnectionFailure(IOException ex) {
+                failed.countDown();
+            }
+        });
+
+        provider.connect();
+
+        assertTrue(failed.await(2, TimeUnit.SECONDS));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsFailoverTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsFailoverTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsFailoverTest.java
new file mode 100644
index 0000000..d615f3d
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsFailoverTest.java
@@ -0,0 +1,283 @@
+/**
+ * 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.jms.failover;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.DeliveryMode;
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.Topic;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Basic tests for the FailoverProvider implementation
+ */
+public class JmsFailoverTest extends AmqpTestSupport {
+
+    @Override
+    protected boolean isPersistent() {
+        return true;
+    }
+
+    @Test(timeout=60000)
+    public void testFailoverConnects() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testFailoverConnectsWithMultipleURIs() throws Exception {
+        URI brokerURI = new URI("failover://(amqp://127.0.0.1:61616,amqp://localhost:5777," +
+                                getBrokerAmqpConnectionURI() + ")?maxReconnectDelay=500");
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+        connection.close();
+    }
+
+    @Test(timeout=60000, expected=JMSException.class)
+    public void testStartupReconnectAttempts() throws Exception {
+        URI brokerURI = new URI("failover://(amqp://localhost:61616)" +
+                                "?maxReconnectDelay=1000&startupMaxReconnectAttempts=5");
+        JmsConnectionFactory factory = new JmsConnectionFactory(brokerURI);
+        Connection connection = factory.createConnection();
+        connection.start();
+    }
+
+    @Test(timeout=60000, expected=JMSException.class)
+    public void testStartupReconnectAttemptsMultipleHosts() throws Exception {
+        URI brokerURI = new URI("failover://(amqp://localhost:61616,amqp://localhost:61617)" +
+                                "?maxReconnectDelay=1000&startupMaxReconnectAttempts=5");
+        JmsConnectionFactory factory = new JmsConnectionFactory(brokerURI);
+        Connection connection = factory.createConnection();
+        connection.start();
+    }
+
+    @Test(timeout=60000)
+    public void testStartFailureWithAsyncExceptionListener() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI() + "?maxReconnectDelay=1000&maxReconnectAttempts=5");
+
+        final CountDownLatch failed = new CountDownLatch(1);
+        JmsConnectionFactory factory = new JmsConnectionFactory(brokerURI);
+        factory.setExceptionListener(new ExceptionListener() {
+
+            @Override
+            public void onException(JMSException exception) {
+                LOG.info("Connection got exception: {}", exception.getMessage());
+                failed.countDown();
+            }
+        });
+        Connection connection = factory.createConnection();
+        connection.start();
+
+        stopPrimaryBroker();
+
+        assertTrue("No async exception", failed.await(15, TimeUnit.SECONDS));
+    }
+
+    @SuppressWarnings("unused")
+    @Test(timeout=60000)
+    public void testBasicStateRestoration() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI() + "?maxReconnectDelay=1000");
+
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        assertEquals(1, brokerService.getAdminView().getQueueSubscribers().length);
+        assertEquals(1, brokerService.getAdminView().getQueueProducers().length);
+
+        restartPrimaryBroker();
+
+        assertTrue("Should have a new connection.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return brokerService.getAdminView().getCurrentConnectionsCount() == 1;
+            }
+        }));
+
+        assertEquals(1, brokerService.getAdminView().getQueueSubscribers().length);
+        assertEquals(1, brokerService.getAdminView().getQueueProducers().length);
+
+        connection.close();
+    }
+
+    @SuppressWarnings("unused")
+    @Test(timeout=60000)
+    public void testDurableSubscriberRestores() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI() + "?maxReconnectDelay=1000");
+
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.setClientID(name.getMethodName());
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Topic topic = session.createTopic(name.getMethodName());
+        MessageConsumer consumer = session.createDurableSubscriber(topic, name.getMethodName());
+
+        assertEquals(1, brokerService.getAdminView().getDurableTopicSubscribers().length);
+
+        restartPrimaryBroker();
+
+        assertTrue("Should have a new connection.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return brokerService.getAdminView().getCurrentConnectionsCount() == 1;
+            }
+        }));
+
+        assertTrue("Should have no inactive subscribers.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return brokerService.getAdminView().getInactiveDurableTopicSubscribers().length == 0;
+            }
+        }));
+
+        assertTrue("Should have one durable sub.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return brokerService.getAdminView().getDurableTopicSubscribers().length == 1;
+            }
+        }));
+
+        connection.close();
+    }
+
+    @Test(timeout=90000)
+    public void testBadFirstURIConnectsAndProducerWorks() throws Exception {
+        URI brokerURI = new URI("failover://(amqp://localhost:61616," +
+                                             getBrokerAmqpConnectionURI() + ")?maxReconnectDelay=1000");
+
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        final int MSG_COUNT = 10;
+        final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        final MessageProducer producer = session.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+        final CountDownLatch failed = new CountDownLatch(1);
+
+        assertEquals(1, brokerService.getAdminView().getQueueProducers().length);
+
+        for (int i = 0; i < MSG_COUNT; ++i) {
+            producer.send(session.createTextMessage("Message: " + i));
+        }
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+
+        assertTrue("Should have all messages sent.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == MSG_COUNT;
+            }
+        }));
+
+        assertFalse(failed.getCount() == 0);
+        connection.close();
+    }
+
+    // TODO - FIXME
+    @Ignore("Test currently not working")
+    @Test(timeout=90000)
+    public void testProducerBlocksAndRecovers() throws Exception {
+        URI brokerURI = new URI("failover://("+ getBrokerAmqpConnectionURI() +")?maxReconnectDelay=1000");
+
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        final int MSG_COUNT = 10;
+        final Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        final MessageProducer producer = session.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+        final CountDownLatch failed = new CountDownLatch(1);
+
+        assertEquals(1, brokerService.getAdminView().getQueueProducers().length);
+
+        Thread producerThread = new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    for (int i = 0; i < MSG_COUNT; ++i) {
+                        producer.send(session.createTextMessage("Message: " + i));
+                        TimeUnit.SECONDS.sleep(1);
+                    }
+                } catch (Exception e) {
+                }
+            }
+        });
+        producerThread.start();
+
+        TimeUnit.SECONDS.sleep(3);
+        stopPrimaryBroker();
+        TimeUnit.SECONDS.sleep(3);
+        restartPrimaryBroker();
+
+        assertTrue("Should have a new connection.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return brokerService.getAdminView().getCurrentConnectionsCount() == 1;
+            }
+        }));
+
+        assertEquals(1, brokerService.getAdminView().getQueueProducers().length);
+
+        final QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+
+        assertTrue("Should have all messages sent.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return proxy.getQueueSize() == MSG_COUNT;
+            }
+        }));
+
+        assertFalse(failed.getCount() == 0);
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsOfflineBehaviorTests.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsOfflineBehaviorTests.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsOfflineBehaviorTests.java
new file mode 100644
index 0000000..bc971f6
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/failover/JmsOfflineBehaviorTests.java
@@ -0,0 +1,196 @@
+/**
+ * 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.jms.failover;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.Connection;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.provider.Provider;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.apache.qpid.jms.support.Wait;
+import org.junit.Test;
+
+/**
+ * Test various client behaviors when the connection has gone offline.
+ */
+public class JmsOfflineBehaviorTests extends AmqpTestSupport {
+
+    @Test(timeout=60000)
+    public void testConnectionCloseDoesNotBlock() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+        stopPrimaryBroker();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testSessionCloseDoesNotBlock() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        stopPrimaryBroker();
+        session.close();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testClientAckDoesNotBlock() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        MessageProducer producer = session.createProducer(queue);
+        producer.send(session.createTextMessage("Test"));
+
+        Message message = consumer.receive(5000);
+        assertNotNull(message);
+        stopPrimaryBroker();
+        message.acknowledge();
+
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testProducerCloseDoesNotBlock() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+
+        stopPrimaryBroker();
+        producer.close();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testConsumerCloseDoesNotBlock() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        stopPrimaryBroker();
+        consumer.close();
+        connection.close();
+    }
+
+    @SuppressWarnings("unused")
+    @Test(timeout=60000)
+    public void testSessionCloseWithOpenResourcesDoesNotBlock() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI());
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        MessageProducer producer = session.createProducer(queue);
+
+        stopPrimaryBroker();
+        session.close();
+        connection.close();
+    }
+
+    @Test(timeout=60000)
+    public void testGetRemoteURI() throws Exception {
+
+        startNewBroker();
+
+        URI brokerURI = new URI(getAmqpFailoverURI() + "randomize=false");
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        JmsConnection jmsConnection = (JmsConnection) connection;
+        final Provider provider = jmsConnection.getProvider();
+
+        URI connectedURI = provider.getRemoteURI();
+        assertNotNull(connectedURI);
+
+        final List<URI> brokers = getBrokerURIs();
+        assertEquals(brokers.get(0), connectedURI);
+
+        stopPrimaryBroker();
+
+        assertTrue("Should connect to secondary URI.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return provider.getRemoteURI().equals(brokers.get(1));
+            }
+        }));
+
+        connection.close();
+    }
+
+    @SuppressWarnings("unused")
+    @Test(timeout=60000)
+    public void testClosedReourcesAreNotRestored() throws Exception {
+        URI brokerURI = new URI(getAmqpFailoverURI() + "?maxReconnectDelay=500");
+        Connection connection = createAmqpConnection(brokerURI);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageConsumer consumer = session.createConsumer(queue);
+        MessageProducer producer = session.createProducer(queue);
+
+        assertEquals(1, brokerService.getAdminView().getQueueSubscribers().length);
+        assertEquals(1, brokerService.getAdminView().getQueueProducers().length);
+
+        stopPrimaryBroker();
+        session.close();
+        TimeUnit.SECONDS.sleep(2);
+        restartPrimaryBroker();
+
+        assertTrue("Should have a new connection.", Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return brokerService.getAdminView().getCurrentConnectionsCount() == 1;
+            }
+        }));
+
+        assertEquals(0, brokerService.getAdminView().getQueueSubscribers().length);
+        assertEquals(0, brokerService.getAdminView().getQueueProducers().length);
+
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/ActiveMQAdmin.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/ActiveMQAdmin.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/ActiveMQAdmin.java
new file mode 100644
index 0000000..f1e7db1
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/ActiveMQAdmin.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.jms.joram;
+
+import java.io.File;
+import java.net.URI;
+import java.util.Hashtable;
+
+import javax.jms.ConnectionFactory;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.apache.activemq.broker.BrokerFactory;
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.JmsTopic;
+import org.objectweb.jtests.jms.admin.Admin;
+
+/**
+ *
+ */
+public class ActiveMQAdmin implements Admin {
+
+    Context context;
+    {
+        try {
+            // Use the jetty JNDI context since it's mutable.
+            final Hashtable<String, String> env = new Hashtable<String, String>();
+            env.put("java.naming.factory.initial", "org.eclipse.jetty.jndi.InitialContextFactory");
+            env.put("java.naming.factory.url.pkgs", "org.eclipse.jetty.jndi");
+            ;
+            context = new InitialContext(env);
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected BrokerService createBroker() throws Exception {
+        return BrokerFactory.createBroker(new URI("broker://()/localhost?persistent=false"));
+    }
+
+    @Override
+    public String getName() {
+        return getClass().getName();
+    }
+
+    static BrokerService broker;
+    static int port;
+
+    @Override
+    public void startServer() throws Exception {
+        if (broker != null) {
+            stopServer();
+        }
+        if (System.getProperty("basedir") == null) {
+            File file = new File(".");
+            System.setProperty("basedir", file.getAbsolutePath());
+        }
+        broker = createBroker();
+        TransportConnector connector = broker.addConnector(getConnectorURI());
+        broker.start();
+        port = connector.getConnectUri().getPort();
+    }
+
+    protected String getConnectorURI() {
+        return "amqp://localhost:0";
+    }
+
+    @Override
+    public void stopServer() throws Exception {
+        broker.stop();
+        broker = null;
+    }
+
+    @Override
+    public void start() throws Exception {
+    }
+
+    @Override
+    public void stop() throws Exception {
+    }
+
+    @Override
+    public Context createContext() throws NamingException {
+        return context;
+    }
+
+    @Override
+    public void createQueue(String name) {
+        try {
+            context.bind(name, new JmsQueue(name));
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void createTopic(String name) {
+        try {
+            context.bind(name, new JmsTopic(name));
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void deleteQueue(String name) {
+        try {
+            context.unbind(name);
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void deleteTopic(String name) {
+        try {
+            context.unbind(name);
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void createConnectionFactory(String name) {
+        try {
+            final ConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:" + port);
+            context.bind(name, factory);
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void deleteConnectionFactory(String name) {
+        try {
+            context.unbind(name);
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void createQueueConnectionFactory(String name) {
+        createConnectionFactory(name);
+    }
+
+    @Override
+    public void createTopicConnectionFactory(String name) {
+        createConnectionFactory(name);
+    }
+
+    @Override
+    public void deleteQueueConnectionFactory(String name) {
+        deleteConnectionFactory(name);
+    }
+
+    @Override
+    public void deleteTopicConnectionFactory(String name) {
+        deleteConnectionFactory(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/JoramJmsTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/JoramJmsTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/JoramJmsTest.java
new file mode 100644
index 0000000..3e59b69
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/joram/JoramJmsTest.java
@@ -0,0 +1,71 @@
+/**
+ * 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.jms.joram;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.objectweb.jtests.jms.conform.connection.ConnectionTest;
+import org.objectweb.jtests.jms.conform.connection.TopicConnectionTest;
+import org.objectweb.jtests.jms.conform.message.MessageBodyTest;
+import org.objectweb.jtests.jms.conform.message.MessageDefaultTest;
+import org.objectweb.jtests.jms.conform.message.headers.MessageHeaderTest;
+import org.objectweb.jtests.jms.conform.message.properties.MessagePropertyConversionTest;
+import org.objectweb.jtests.jms.conform.message.properties.MessagePropertyTest;
+import org.objectweb.jtests.jms.conform.queue.TemporaryQueueTest;
+import org.objectweb.jtests.jms.conform.selector.SelectorSyntaxTest;
+import org.objectweb.jtests.jms.conform.selector.SelectorTest;
+import org.objectweb.jtests.jms.conform.session.QueueSessionTest;
+import org.objectweb.jtests.jms.conform.topic.TemporaryTopicTest;
+
+public class JoramJmsTest extends TestCase {
+
+    public static Test suite() {
+        TestSuite suite = new TestSuite();
+
+        // TODO: Fix these tests..
+        // Fails due to
+        // https://issues.apache.org/jira/browse/PROTON-154
+        // suite.addTestSuite(TopicSessionTest.class);
+
+//        suite.addTestSuite(MessageTypeTest.class);
+//        suite.addTestSuite(UnifiedSessionTest.class);
+//        suite.addTestSuite(JMSXPropertyTest.class);
+//        suite.addTestSuite(SessionTest.class);
+
+//        suite.addTestSuite(QueueBrowserTest.class);
+        suite.addTestSuite(QueueSessionTest.class);
+        suite.addTestSuite(SelectorSyntaxTest.class);
+        suite.addTestSuite(SelectorTest.class);
+        suite.addTestSuite(MessageHeaderTest.class);
+        suite.addTestSuite(TemporaryTopicTest.class);
+        suite.addTestSuite(TemporaryQueueTest.class);
+        suite.addTestSuite(TopicConnectionTest.class);
+        suite.addTestSuite(ConnectionTest.class);
+        suite.addTestSuite(MessageBodyTest.class);
+        suite.addTestSuite(MessageDefaultTest.class);
+        suite.addTestSuite(MessagePropertyConversionTest.class);
+        suite.addTestSuite(MessagePropertyTest.class);
+
+        return suite;
+    }
+
+    public static void main(String[] args) {
+        junit.textui.TestRunner.run(suite());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsAnonymousProducerTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsAnonymousProducerTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsAnonymousProducerTest.java
new file mode 100644
index 0000000..04b954a
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsAnonymousProducerTest.java
@@ -0,0 +1,93 @@
+/**
+ * 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.jms.producer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test JMS Anonymous Producer functionality.
+ */
+public class JmsAnonymousProducerTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateProducer() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        session.createProducer(null);
+
+        assertTrue(brokerService.getAdminView().getTotalProducerCount() == 0);
+    }
+
+    @Test(timeout = 60000)
+    public void testAnonymousSend() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue(name.getMethodName());
+        assertNotNull(session);
+        MessageProducer producer = session.createProducer(null);
+
+        Message message = session.createMessage();
+        producer.send(queue, message);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testAnonymousSendToMultipleDestinations() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue1 = session.createQueue(name.getMethodName() + 1);
+        Queue queue2 = session.createQueue(name.getMethodName() + 2);
+        Queue queue3 = session.createQueue(name.getMethodName() + 3);
+        assertNotNull(session);
+        MessageProducer producer = session.createProducer(null);
+
+        Message message = session.createMessage();
+        producer.send(queue1, message);
+        producer.send(queue2, message);
+        producer.send(queue3, message);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName() + 1);
+        assertEquals(1, proxy.getQueueSize());
+        proxy = getProxyToQueue(name.getMethodName() + 2);
+        assertEquals(1, proxy.getQueueSize());
+        proxy = getProxyToQueue(name.getMethodName() + 3);
+        assertEquals(1, proxy.getQueueSize());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerClosedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerClosedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerClosedTest.java
new file mode 100644
index 0000000..a7b8cdf
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerClosedTest.java
@@ -0,0 +1,133 @@
+/**
+ * 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.jms.producer;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test the contract of MessageProducer that has been closed.
+ */
+public class JmsMessageProducerClosedTest extends AmqpTestSupport {
+
+    protected MessageProducer producer;
+    protected Message message;
+    protected Destination destination;
+
+    protected MessageProducer createProducer() throws Exception {
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        message = session.createMessage();
+        destination = session.createTopic("test");
+        MessageProducer producer = session.createProducer(destination);
+        producer.close();
+        return producer;
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        producer = createProducer();
+    }
+
+    @Test(timeout=30000)
+    public void testClose() throws JMSException {
+        producer.close();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetDisableMessageIDFails() throws JMSException {
+        producer.setDisableMessageID(true);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetDisableMessageIDFails() throws JMSException {
+        producer.getDisableMessageID();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetDisableMessageTimestampFails() throws JMSException {
+        producer.setDisableMessageTimestamp(false);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetDisableMessageTimestampFails() throws JMSException {
+        producer.getDisableMessageTimestamp();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetDeliveryModeFails() throws JMSException {
+        producer.setDeliveryMode(1);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetDeliveryModeFails() throws JMSException {
+        producer.getDeliveryMode();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetPriorityFails() throws JMSException {
+        producer.setPriority(1);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetPriorityFails() throws JMSException {
+        producer.getPriority();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSetTimeToLiveFails() throws JMSException {
+        producer.setTimeToLive(1);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetTimeToLiveFails() throws JMSException {
+        producer.getTimeToLive();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testGetDestinationFails() throws JMSException {
+        producer.getDestination();
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSendFails() throws JMSException {
+        producer.send(message);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSendWithDestinationFails() throws JMSException {
+        producer.send(destination, message);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSendWithModePriorityTTLFails() throws JMSException {
+        producer.send(message, 1, 3, 111);
+    }
+
+    @Test(timeout=30000, expected=JMSException.class)
+    public void testSendWithDestinationModePriorityTTLFails() throws JMSException {
+        producer.send(destination, message, 1, 3, 111);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerFailedTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerFailedTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerFailedTest.java
new file mode 100644
index 0000000..b6f5011
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerFailedTest.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.jms.producer;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.support.Wait;
+
+/**
+ * Tests the MessageProducer method contract when it's connection has failed.
+ */
+public class JmsMessageProducerFailedTest extends JmsMessageProducerClosedTest {
+
+    @Override
+    protected MessageProducer createProducer() throws Exception {
+        final CountDownLatch latch = new CountDownLatch(1);
+        connection = createAmqpConnection();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        message = session.createMessage();
+        destination = session.createQueue("test");
+        MessageProducer producer = session.createProducer(destination);
+        connection.setExceptionListener(new ExceptionListener() {
+
+            @Override
+            public void onException(JMSException exception) {
+                latch.countDown();
+            }
+        });
+        connection.start();
+        stopPrimaryBroker();
+        assertTrue(latch.await(10, TimeUnit.SECONDS));
+        final JmsConnection jmsConnection = (JmsConnection) connection;
+        assertTrue(Wait.waitFor(new Wait.Condition() {
+
+            @Override
+            public boolean isSatisified() throws Exception {
+                return !jmsConnection.isConnected();
+            }
+        }));
+        return producer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerTest.java
new file mode 100644
index 0000000..ceb2d53
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsMessageProducerTest.java
@@ -0,0 +1,193 @@
+/**
+ * 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.jms.producer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.DeliveryMode;
+import javax.jms.JMSSecurityException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JmsMessageProducerTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testCreateMessageProducer() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        session.createProducer(queue);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+    }
+
+    @Test
+    public void testSendWorksWhenConnectionNotStarted() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+
+        Message message = session.createMessage();
+        producer.send(message);
+
+        assertEquals(1, proxy.getQueueSize());
+    }
+
+    @Test
+    public void testSendWorksAfterConnectionStopped() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+        connection.stop();
+
+        Message message = session.createMessage();
+        producer.send(message);
+
+        assertEquals(1, proxy.getQueueSize());
+    }
+
+    @Test
+    public void testPersistentSendsAreMarkedPersistent() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+
+        Message message = session.createMessage();
+        producer.send(message);
+
+        assertEquals(1, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        message = consumer.receive(5000);
+        assertNotNull(message);
+        assertTrue(message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT);
+    }
+
+    @Test
+    public void testProducerWithNoTTLSendsMessagesWithoutTTL() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+
+        Message message = session.createMessage();
+        producer.send(message);
+
+        assertEquals(1, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        message = consumer.receive(5000);
+        assertNotNull(message);
+        assertEquals(0, message.getJMSExpiration());
+    }
+
+    private String createLargeString(int sizeInBytes) {
+        byte[] base = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < sizeInBytes; i++) {
+            builder.append(base[i % base.length]);
+        }
+
+        LOG.debug("Created string with size : " + builder.toString().getBytes().length + " bytes");
+        return builder.toString();
+    }
+
+    @Test(timeout = 60 * 1000)
+    public void testSendLargeMessage() throws Exception {
+        connection = createAmqpConnection();
+        assertNotNull(connection);
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        String queueName = name.toString();
+        Queue queue = session.createQueue(queueName);
+
+        MessageProducer producer = session.createProducer(queue);
+        int messageSize = 1024 * 1024;
+        String messageText = createLargeString(messageSize);
+        Message m = session.createTextMessage(messageText);
+        LOG.debug("Sending message of {} bytes on queue {}", messageSize, queueName);
+        producer.send(m);
+
+        MessageConsumer consumer = session.createConsumer(queue);
+
+        Message message = consumer.receive();
+        assertNotNull(message);
+        assertTrue(message instanceof TextMessage);
+        TextMessage textMessage = (TextMessage) message;
+        LOG.debug(">>>> Received message of length {}", textMessage.getText().length());
+        assertEquals(messageSize, textMessage.getText().length());
+        assertEquals(messageText, textMessage.getText());
+    }
+
+    @Test(timeout=90000, expected=JMSSecurityException.class)
+    public void testProducerNotAuthorized() throws Exception{
+        connection = createAmqpConnection("guest", "password");
+        connection.start();
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        Queue queue = session.createQueue("USERS." + name.getMethodName());
+        session.createProducer(queue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsProduceMessageTypesTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsProduceMessageTypesTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsProduceMessageTypesTest.java
new file mode 100644
index 0000000..5ba9f9e
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsProduceMessageTypesTest.java
@@ -0,0 +1,171 @@
+/**
+ * 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.jms.producer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jms.BytesMessage;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test basic MessageProducer functionality.
+ */
+public class JmsProduceMessageTypesTest extends AmqpTestSupport {
+
+    @Test(timeout = 60000)
+    public void testSendJMSMessage() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        Message message = session.createMessage();
+        producer.send(message);
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+    }
+
+    @Test(timeout = 60000)
+    public void testSendJMSBytesMessage() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        String payload = "TEST";
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        BytesMessage message = session.createBytesMessage();
+        message.writeUTF(payload);
+        producer.send(message);
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message received = consumer.receive(5000);
+        assertNotNull(received);
+        assertTrue(received instanceof BytesMessage);
+        BytesMessage bytes = (BytesMessage) received;
+        assertEquals(payload, bytes.readUTF());
+    }
+
+    @Test(timeout = 60000)
+    public void testSendJMSMapMessage() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        MapMessage message = session.createMapMessage();
+        message.setBoolean("Boolean", false);
+        message.setString("STRING", "TEST");
+        producer.send(message);
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message received = consumer.receive(5000);
+        assertNotNull(received);
+        assertTrue(received instanceof MapMessage);
+        MapMessage map = (MapMessage) received;
+        assertEquals("TEST", map.getString("STRING"));
+        assertEquals(false, map.getBooleanProperty("Boolean"));
+    }
+
+    @Test(timeout = 60000)
+    public void testSendJMSStreamMessage() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        String payload = "TEST";
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        StreamMessage message = session.createStreamMessage();
+        message.writeString(payload);
+        producer.send(message);
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message received = consumer.receive(5000);
+        assertNotNull(received);
+        assertTrue(received instanceof StreamMessage);
+        StreamMessage stream = (StreamMessage) received;
+        assertEquals(payload, stream.readString());
+    }
+
+    @Test(timeout = 60000)
+    public void testSendJMSTextMessage() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        String payload = "TEST";
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        TextMessage message = session.createTextMessage("TEST");
+        producer.send(message);
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+
+        MessageConsumer consumer = session.createConsumer(queue);
+        Message received = consumer.receive(5000);
+        assertNotNull(received);
+        assertTrue(received instanceof TextMessage);
+        TextMessage text = (TextMessage) received;
+        assertEquals(payload, text.getText());
+    }
+
+    @Test(timeout = 60000)
+    public void testSendJMSObjectMessage() throws Exception {
+        connection = createAmqpConnection();
+        connection.start();
+
+        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        MessageProducer producer = session.createProducer(queue);
+        ObjectMessage message = session.createObjectMessage("TEST");
+        producer.send(message);
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(1, proxy.getQueueSize());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsQueueSenderTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsQueueSenderTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsQueueSenderTest.java
new file mode 100644
index 0000000..e4c0910
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsQueueSenderTest.java
@@ -0,0 +1,54 @@
+/**
+ * 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.jms.producer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
+
+import org.apache.activemq.broker.jmx.QueueViewMBean;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * Test basic QueueSender functionality.
+ */
+public class JmsQueueSenderTest extends AmqpTestSupport {
+
+    @Test
+    public void testCreateQueueSender() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        QueueConnection connection = factory.createQueueConnection();
+        assertNotNull(connection);
+
+        QueueSession session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Queue queue = session.createQueue(name.getMethodName());
+        QueueSender sender = session.createSender(queue);
+        assertNotNull(sender);
+
+        QueueViewMBean proxy = getProxyToQueue(name.getMethodName());
+        assertEquals(0, proxy.getQueueSize());
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsTopicPublisherTest.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsTopicPublisherTest.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsTopicPublisherTest.java
new file mode 100644
index 0000000..80c4215
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/producer/JmsTopicPublisherTest.java
@@ -0,0 +1,54 @@
+/**
+ * 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.jms.producer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import javax.jms.Session;
+import javax.jms.Topic;
+import javax.jms.TopicConnection;
+import javax.jms.TopicPublisher;
+import javax.jms.TopicSession;
+
+import org.apache.activemq.broker.jmx.TopicViewMBean;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.support.AmqpTestSupport;
+import org.junit.Test;
+
+/**
+ * test basic TopicPublisher functionality.
+ */
+public class JmsTopicPublisherTest extends AmqpTestSupport {
+
+    @Test
+    public void testCreateTopicPublisher() throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(getBrokerAmqpConnectionURI());
+        TopicConnection connection = factory.createTopicConnection();
+        assertNotNull(connection);
+
+        TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+        assertNotNull(session);
+        Topic topic = session.createTopic(name.getMethodName());
+        TopicPublisher publisher = session.createPublisher(topic);
+        assertNotNull(publisher);
+
+        TopicViewMBean proxy = getProxyToTopic(name.getMethodName());
+        assertEquals(0, proxy.getEnqueueCount());
+        connection.close();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/AmqpTestSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/AmqpTestSupport.java b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/AmqpTestSupport.java
new file mode 100644
index 0000000..0e1d247
--- /dev/null
+++ b/qpid-jms-interop-tests/qpid-jms-activemq-tests/src/test/java/org/apache/qpid/jms/support/AmqpTestSupport.java
@@ -0,0 +1,145 @@
+/**
+ * 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.jms.support;
+
+import java.net.URI;
+import java.util.Map;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+
+import org.apache.activemq.broker.BrokerService;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AmqpTestSupport extends QpidJmsTestSupport {
+
+    protected static final Logger LOG = LoggerFactory.getLogger(AmqpTestSupport.class);
+
+    protected boolean isAmqpDiscovery() {
+        return false;
+    }
+
+    protected String getAmqpTransformer() {
+        return "jms";
+    }
+
+    protected int getSocketBufferSize() {
+        return 64 * 1024;
+    }
+
+    protected int getIOBufferSize() {
+        return 8 * 1024;
+    }
+
+    @Override
+    protected void addAdditionalConnectors(BrokerService brokerService, Map<String, Integer> portMap) throws Exception {
+        int port = 0;
+        if (portMap.containsKey("amqp")) {
+            port = portMap.get("amqp");
+        }
+        TransportConnector connector = brokerService.addConnector(
+            "amqp://0.0.0.0:" + port + "?transport.transformer=" + getAmqpTransformer() +
+            "&transport.socketBufferSize=" + getSocketBufferSize() + "&ioBufferSize=" + getIOBufferSize());
+        connector.setName("amqp");
+        if (isAmqpDiscovery()) {
+            connector.setDiscoveryUri(new URI("multicast://default"));
+        }
+        port = connector.getPublishableConnectURI().getPort();
+        LOG.debug("Using amqp port: {}", port);
+    }
+
+    public String getAmqpConnectionURIOptions() {
+        return "";
+    }
+
+    public URI getBrokerAmqpConnectionURI() {
+        try {
+            String uri = "amqp://127.0.0.1:" +
+                brokerService.getTransportConnectorByName("amqp").getPublishableConnectURI().getPort();
+
+            if (!getAmqpConnectionURIOptions().isEmpty()) {
+                uri = uri + "?" + getAmqpConnectionURIOptions();
+            }
+
+            return new URI(uri);
+        } catch (Exception e) {
+            throw new RuntimeException();
+        }
+    }
+
+    public String getAmqpFailoverURI() throws Exception {
+        StringBuilder uri = new StringBuilder();
+        uri.append("failover://(");
+        uri.append(brokerService.getTransportConnectorByName("amqp").getPublishableConnectString());
+
+        for (BrokerService broker : brokers) {
+            uri.append(",");
+            uri.append(broker.getTransportConnectorByName("amqp").getPublishableConnectString());
+        }
+
+        uri.append(")");
+
+        return uri.toString();
+    }
+
+    public Connection createAmqpConnection() throws Exception {
+        return createAmqpConnection(getBrokerAmqpConnectionURI());
+    }
+
+    public Connection createAmqpConnection(String username, String password) throws Exception {
+        return createAmqpConnection(getBrokerAmqpConnectionURI(), username, password);
+    }
+
+    public Connection createAmqpConnection(URI brokerURI) throws Exception {
+        return createAmqpConnection(brokerURI, null, null);
+    }
+
+    public Connection createAmqpConnection(URI brokerURI, String username, String password) throws Exception {
+        ConnectionFactory factory = createAmqpConnectionFactory(brokerURI, username, password);
+        return factory.createConnection();
+    }
+
+    public ConnectionFactory createAmqpConnectionFactory() throws Exception {
+        return createAmqpConnectionFactory(getBrokerAmqpConnectionURI(), null, null);
+    }
+
+    public ConnectionFactory createAmqpConnectionFactory(URI brokerURI) throws Exception {
+        return createAmqpConnectionFactory(brokerURI, null, null);
+    }
+
+    public ConnectionFactory createAmqpConnectionFactory(String username, String password) throws Exception {
+        return createAmqpConnectionFactory(getBrokerAmqpConnectionURI(), username, password);
+    }
+
+    public ConnectionFactory createAmqpConnectionFactory(URI brokerURI, String username, String password) throws Exception {
+        JmsConnectionFactory factory = new JmsConnectionFactory(brokerURI);
+        factory.setForceAsyncSend(isForceAsyncSends());
+        factory.setAlwaysSyncSend(isAlwaysSyncSend());
+        factory.setMessagePrioritySupported(isMessagePrioritySupported());
+        factory.setSendAcksAsync(isSendAcksAsync());
+        if (username != null) {
+            factory.setUsername(username);
+        }
+        if (password != null) {
+            factory.setPassword(password);
+        }
+        return factory;
+    }
+}
\ No newline at end of file


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


[17/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
new file mode 100644
index 0000000..1131829
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFacade.java
@@ -0,0 +1,674 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_AMQP_TTL;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MESSAGE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsMessageId;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.Proton;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ *
+ */
+public class AmqpJmsMessageFacade implements JmsMessageFacade {
+
+    private static final int DEFAULT_PRIORITY = javax.jms.Message.DEFAULT_PRIORITY;
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+    private static final long MAX_UINT = 0xFFFFFFFFL;
+
+    protected final Message message;
+    protected final AmqpConnection connection;
+
+    private MessageAnnotations annotations;
+    private Map<Symbol,Object> annotationsMap;
+    private Map<String,Object> propertiesMap;
+
+    private JmsDestination replyTo;
+    private JmsDestination destination;
+
+    private Long syntheticTTL;
+
+    /**
+     * Used to record the value of JMS_AMQP_TTL property
+     * if it is explicitly set by the application
+     */
+    private Long userSpecifiedTTL = null;
+
+    /**
+     * Create a new AMQP Message Facade with an empty message instance.
+     */
+    public AmqpJmsMessageFacade(AmqpConnection connection) {
+        this.message = Proton.message();
+        this.message.setDurable(true);
+
+        this.connection = connection;
+        setAnnotation(JMS_MSG_TYPE, JMS_MESSAGE);
+    }
+
+    /**
+     * Creates a new Facade around an incoming AMQP Message for dispatch to the
+     * JMS Consumer instance.
+     *
+     * @param connection
+     *        the connection that created this Facade.
+     * @param message
+     *        the incoming Message instance that is being wrapped.
+     */
+    @SuppressWarnings("unchecked")
+    public AmqpJmsMessageFacade(AmqpConnection connection, Message message) {
+        this.message = message;
+        this.connection = connection;
+
+        annotations = message.getMessageAnnotations();
+        if (annotations != null) {
+            annotationsMap = annotations.getValue();
+        }
+
+        if (message.getApplicationProperties() != null) {
+            propertiesMap = message.getApplicationProperties().getValue();
+        }
+
+        Long ttl = message.getTtl();
+        Long absoluteExpiryTime = getAbsoluteExpiryTime();
+        if (absoluteExpiryTime == null && ttl != null) {
+            syntheticTTL = System.currentTimeMillis() + ttl;
+        }
+
+        // TODO - Set destination
+        // TODO - Set replyTo
+    }
+
+    /**
+     * @return the appropriate byte value that indicates the type of message this is.
+     */
+    public byte getJmsMsgType() {
+        return JMS_MESSAGE;
+    }
+
+    /**
+     * The annotation value for the JMS Message content type.  For a generic JMS message this
+     * value is omitted so we return null here, subclasses should override this to return the
+     * correct content type value for their payload.
+     *
+     * @return a String value indicating the message content type.
+     */
+    public String getContentType() {
+        return message.getContentType();
+    }
+
+    public void setContentType(String value) {
+        message.setContentType(value);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return true;
+    }
+
+    @Override
+    public Map<String, Object> getProperties() throws JMSException {
+        lazyCreateProperties();
+        return Collections.unmodifiableMap(new HashMap<String, Object>(propertiesMap));
+    }
+
+    @Override
+    public boolean propertyExists(String key) throws JMSException {
+        return AmqpJmsMessagePropertyIntercepter.getProperty(this, key) != null;
+    }
+
+    public boolean applicationPropertyExists(String key) throws JMSException {
+        if (propertiesMap != null) {
+            return propertiesMap.containsKey(key);
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns a set of all the property names that have been set in this message.
+     *
+     * @return a set of property names in the message or an empty set if none are set.
+     */
+    public Set<String> getPropertyNames() {
+        Set<String> properties = AmqpJmsMessagePropertyIntercepter.getPropertyNames(this);
+        if (propertiesMap != null) {
+            properties.addAll(propertiesMap.keySet());
+        }
+        return properties;
+    }
+
+    @Override
+    public Object getProperty(String key) throws JMSException {
+        return AmqpJmsMessagePropertyIntercepter.getProperty(this, key);
+    }
+
+    public Object getApplicationProperty(String key) throws JMSException {
+        if (propertiesMap != null) {
+            return propertiesMap.get(key);
+        }
+
+        return null;
+    }
+
+    @Override
+    public void setProperty(String key, Object value) throws JMSException {
+        if (key == null) {
+            throw new IllegalArgumentException("Property key must not be null");
+        }
+
+        AmqpJmsMessagePropertyIntercepter.setProperty(this, key, value);
+    }
+
+    public void setApplicationProperty(String key, Object value) throws JMSException {
+        if (propertiesMap == null) {
+            lazyCreateProperties();
+        }
+
+        propertiesMap.put(key, value);
+    }
+
+    @Override
+    public void onSend() throws JMSException {
+        String contentType = getContentType();
+        byte jmsMsgType = getJmsMsgType();
+
+        if (contentType != null) {
+            message.setContentType(contentType);
+        }
+        setAnnotation(JMS_MSG_TYPE, jmsMsgType);
+    }
+
+    @Override
+    public void clearBody() {
+        message.setBody(null);
+    }
+
+    @Override
+    public void clearProperties() {
+        clearProperties();
+        //_propJMS_AMQP_TTL = null;
+        message.setReplyToGroupId(null);
+        message.setUserId(null);
+        message.setGroupId(null);
+        setGroupSequence(0);
+
+        // TODO - Clear others as needed.
+    }
+
+    @Override
+    public JmsMessageFacade copy() throws JMSException {
+        AmqpJmsMessageFacade copy = new AmqpJmsMessageFacade(connection, message);
+        copyInto(copy);
+        return copy;
+    }
+
+    protected void copyInto(AmqpJmsMessageFacade target) {
+        // TODO - Copy message.
+    }
+
+    @Override
+    public JmsMessageId getMessageId() {
+        Object result = message.getMessageId();
+        if (result != null) {
+            if (result instanceof String) {
+                return new JmsMessageId((String) result);
+            } else {
+                // TODO
+                throw new RuntimeException("No support for non-String IDs yet.");
+            }
+        }
+
+        //TODO: returning a null JmsMessageId object leads to NPE during delivery processing
+        return null;
+    }
+
+    @Override
+    public void setMessageId(JmsMessageId messageId) {
+        if (messageId != null) {
+            message.setMessageId(messageId.toString());
+        } else {
+            message.setMessageId(null);
+        }
+    }
+
+    @Override
+    public long getTimestamp() {
+        if (message.getProperties() != null) {
+            Date timestamp = message.getProperties().getCreationTime();
+            if (timestamp != null) {
+                return timestamp.getTime();
+            }
+        }
+
+        return 0L;
+    }
+
+    @Override
+    public void setTimestamp(long timestamp) {
+        if (message.getProperties() != null) {
+            if (timestamp != 0) {
+                message.setCreationTime(timestamp);
+            } else {
+                message.getProperties().setCreationTime(null);
+            }
+        }
+    }
+
+    @Override
+    public String getCorrelationId() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void setCorrelationId(String correlationId) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public byte[] getCorrelationIdBytes() throws JMSException {
+        Object correlationId = message.getCorrelationId();
+        if (correlationId == null) {
+            return null;
+        } else if (correlationId instanceof ByteBuffer) {
+            ByteBuffer dup = ((ByteBuffer) correlationId).duplicate();
+            byte[] bytes = new byte[dup.remaining()];
+            dup.get(bytes);
+            return bytes;
+        } else {
+            // TODO - Do we need to throw here, or could we just stringify whatever is in
+            //        there and return the UTF-8 bytes?  This method is pretty useless so
+            //        maybe we just return something and let the user sort if out if they
+            //        really think they need this.
+            throw new JMSException("The underlying correlation-id is not binary and so can't be returned");
+        }
+    }
+
+    @Override
+    public void setCorrelationIdBytes(byte[] correlationId) {
+        if (correlationId == null) {
+            message.setCorrelationId(correlationId);
+        } else {
+            byte[] bytes = Arrays.copyOf(correlationId, correlationId.length);
+            message.setCorrelationId(ByteBuffer.wrap(bytes));
+        }
+    }
+
+    @Override
+    public boolean isPersistent() {
+        return message.isDurable();
+    }
+
+    @Override
+    public void setPersistent(boolean value) {
+        this.message.setDurable(value);
+    }
+
+    @Override
+    public int getRedeliveryCounter() {
+        if (message.getHeader() != null) {
+            UnsignedInteger count = message.getHeader().getDeliveryCount();
+            if (count != null) {
+                return count.intValue();
+            }
+        }
+
+        return 0;
+    }
+
+    @Override
+    public void setRedeliveryCounter(int redeliveryCount) {
+        if (redeliveryCount == 0) {
+            if (message.getHeader() != null) {
+                message.getHeader().setDeliveryCount(null);
+            }
+        } else {
+            message.setDeliveryCount(redeliveryCount);
+        }
+    }
+
+    @Override
+    public boolean isRedelivered() {
+        return getRedeliveryCounter() > 0;
+    }
+
+    @Override
+    public void setRedelivered(boolean redelivered) {
+        if (redelivered) {
+            if (!isRedelivered()) {
+                setRedeliveryCounter(1);
+            }
+        } else {
+            if (isRedelivered()) {
+                setRedeliveryCounter(0);
+            }
+        }
+    }
+
+    @Override
+    public String getType() {
+        return (String) getAnnotation(JMS_MSG_TYPE);
+    }
+
+    @Override
+    public void setType(String type) {
+        setAnnotation(JMS_MSG_TYPE, type);
+    }
+
+    @Override
+    public byte getPriority() {
+        if (message.getHeader() != null) {
+            UnsignedByte priority = message.getHeader().getPriority();
+            if (priority != null) {
+                return priority.byteValue();
+            }
+        }
+
+        return DEFAULT_PRIORITY;
+    }
+
+    @Override
+    public void setPriority(byte priority) {
+        if (priority == DEFAULT_PRIORITY) {
+            if (message.getHeader() == null) {
+                return;
+            } else {
+                message.getHeader().setPriority(null);
+            }
+        } else {
+            message.setPriority(priority);
+        }
+    }
+
+    @Override
+    public long getExpiration() {
+        Long absoluteExpiry = getAbsoluteExpiryTime();
+        if (absoluteExpiry != null) {
+            return absoluteExpiry;
+        }
+
+        if (syntheticTTL != null) {
+            return syntheticTTL;
+        }
+
+        return 0;
+    }
+
+    @Override
+    public void setExpiration(long expiration) {
+        syntheticTTL = null;
+
+        if (expiration != 0) {
+            setAbsoluteExpiryTime(expiration);
+        } else {
+            setAbsoluteExpiryTime(null);
+        }
+    }
+
+    public void setAmqpTimeToLive(Object value) throws MessageFormatException {
+        Long ttl = null;
+        if (value instanceof Long) {
+            ttl = (Long) value;
+        }
+
+        if (ttl != null && ttl >= 0 && ttl <= MAX_UINT) {
+            userSpecifiedTTL = ttl;
+        } else {
+            throw new MessageFormatException(JMS_AMQP_TTL + " must be a long with value in range 0 to 2^31 - 1");
+        }
+    }
+
+    public long getAmqpTimeToLive() {
+        return userSpecifiedTTL;
+    }
+
+    @Override
+    public JmsDestination getDestination() {
+        return destination;
+    }
+
+    @Override
+    public void setDestination(JmsDestination destination) {
+        this.destination = destination;
+
+        // TODO
+    }
+
+    @Override
+    public JmsDestination getReplyTo() {
+        return replyTo;
+    }
+
+    @Override
+    public void setReplyTo(JmsDestination replyTo) {
+        this.replyTo = replyTo;
+        // TODO Auto-generated method stub
+    }
+
+    public void setReplyToGroupId(String replyToGroupId) {
+        message.setReplyToGroupId(replyToGroupId);
+    }
+
+    public String getReplyToGroupId() {
+        return message.getReplyToGroupId();
+    }
+
+    @Override
+    public String getUserId() {
+        String userId = null;
+        byte[] userIdBytes = message.getUserId();
+
+        if (userIdBytes != null) {
+            userId = new String(userIdBytes, UTF8);
+        }
+
+        return userId;
+    }
+
+    @Override
+    public void setUserId(String userId) {
+        message.setUserId(userId.getBytes(UTF8));
+    }
+
+    @Override
+    public String getGroupId() {
+        return message.getGroupId();
+    }
+
+    @Override
+    public void setGroupId(String groupId) {
+        message.setGroupId(groupId);
+    }
+
+    @Override
+    public int getGroupSequence() {
+        if (message.getProperties() != null) {
+            UnsignedInteger sequence = message.getProperties().getGroupSequence();
+            if (sequence != null) {
+                return sequence.intValue();
+            }
+        }
+
+        return 0;
+    }
+
+    @Override
+    public void setGroupSequence(int groupSequence) {
+        if (groupSequence < 0 && message.getProperties() != null) {
+            message.getProperties().setGroupSequence(null);
+        } else if (groupSequence > 0) {
+            message.setGroupSequence(groupSequence);
+        }
+    }
+
+    /**
+     * @return the true AMQP Message instance wrapped by this Facade.
+     */
+    public Message getAmqpMessage() {
+        return this.message;
+    }
+
+    /**
+     * The AmqpConnection instance that is associated with this Message.
+     * @return
+     */
+    public AmqpConnection getConnection() {
+        return connection;
+    }
+
+    /**
+     * Checks for the presence of a given message annotation and returns true
+     * if it is contained in the current annotations.  If the annotations have
+     * not yet been initialized then this method always returns false.
+     *
+     * @param key
+     *        the name of the annotation to query for.
+     *
+     * @return true if the annotation is present, false in not or annotations not initialized.
+     */
+    boolean annotationExists(String key) {
+        if (annotationsMap == null) {
+            return false;
+        }
+
+        return annotationsMap.containsKey(AmqpMessageSupport.getSymbol(key));
+    }
+
+    /**
+     * Given an annotation name, lookup and return the value associated with that
+     * annotation name.  If the message annotations have not been created yet then
+     * this method will always return null.
+     *
+     * @param key
+     *        the Symbol name that should be looked up in the message annotations.
+     *
+     * @return the value of the annotation if it exists, or null if not set or not accessible.
+     */
+    Object getAnnotation(String key) {
+        if (annotationsMap == null) {
+            return null;
+        }
+
+        return annotationsMap.get(AmqpMessageSupport.getSymbol(key));
+    }
+
+    /**
+     * Removes a message annotation if the message contains it.  Will not do
+     * a lazy create on the message annotations so caller cannot count on the
+     * existence of the message annotations after a call to this method.
+     *
+     * @param key
+     *        the annotation key that is to be removed from the current set.
+     */
+    void removeAnnotation(String key) {
+        if (annotationsMap == null) {
+            return;
+        }
+
+        annotationsMap.remove(AmqpMessageSupport.getSymbol(key));
+    }
+
+    /**
+     * Perform a proper annotation set on the AMQP Message based on a Symbol key and
+     * the target value to append to the current annotations.
+     *
+     * @param key
+     *        The name of the Symbol whose value is being set.
+     * @param value
+     *        The new value to set in the annotations of this message.
+     */
+    void setAnnotation(String key, Object value) {
+        lazyCreateAnnotations();
+        annotationsMap.put(AmqpMessageSupport.getSymbol(key), value);
+    }
+
+    /**
+     * Removes all message annotations from this message.
+     */
+    void clearAnnotations() {
+        annotationsMap = null;
+        annotations = null;
+        message.setMessageAnnotations(null);
+    }
+
+    /**
+     * Removes all application level properties from the Message.
+     */
+    void clearAllApplicationProperties() {
+        propertiesMap = null;
+        message.setApplicationProperties(null);
+    }
+
+    private Long getAbsoluteExpiryTime() {
+        Long result = null;
+        if (message.getProperties() != null) {
+            Date date = message.getProperties().getAbsoluteExpiryTime();
+            if (date != null) {
+                result = date.getTime();
+            }
+        }
+
+        return result;
+    }
+
+    private void setAbsoluteExpiryTime(Long expiration) {
+        if (expiration == null) {
+            if (message.getProperties() != null) {
+                message.getProperties().setAbsoluteExpiryTime(null);
+            }
+        } else {
+            message.setExpiryTime(expiration);
+        }
+    }
+
+    private void lazyCreateAnnotations() {
+        if (annotationsMap == null) {
+            annotationsMap = new HashMap<Symbol,Object>();
+            annotations = new MessageAnnotations(annotationsMap);
+            message.setMessageAnnotations(annotations);
+        }
+    }
+
+    private void lazyCreateProperties() {
+        propertiesMap = new HashMap<String,Object>();
+        message.setApplicationProperties(new ApplicationProperties(propertiesMap));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
new file mode 100644
index 0000000..882c2ac
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessageFactory.java
@@ -0,0 +1,130 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.JmsBytesMessage;
+import org.apache.qpid.jms.message.JmsMapMessage;
+import org.apache.qpid.jms.message.JmsMessage;
+import org.apache.qpid.jms.message.JmsMessageFactory;
+import org.apache.qpid.jms.message.JmsObjectMessage;
+import org.apache.qpid.jms.message.JmsStreamMessage;
+import org.apache.qpid.jms.message.JmsTextMessage;
+import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+import org.apache.qpid.jms.message.facade.JmsTextMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultBytesMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMapMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultObjectMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultStreamMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultTextMessageFacade;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+
+/**
+ * AMQP Message Factory instance used to create new JmsMessage types that wrap an
+ * Proton AMQP Message.  This class is used by the JMS layer to create its JMS
+ * Message instances, the messages returned here should be created in a proper
+ * initially empty state for the client to populate.
+ */
+public class AmqpJmsMessageFactory implements JmsMessageFactory {
+
+    private AmqpConnection connection;
+
+    public AmqpJmsMessageFactory() {
+    }
+
+    public AmqpJmsMessageFactory(AmqpConnection connection) {
+        this.connection = connection;
+    }
+
+    public AmqpConnection getAmqpConnection() {
+        return this.connection;
+    }
+
+    public void setAmqpConnection(AmqpConnection connection) {
+        this.connection = connection;
+    }
+
+    @Override
+    public JmsMessage createMessage() throws JMSException {
+        //return new JmsMessage(new AmqpJmsMessageFacade(connection));
+        return new JmsMessage(new JmsDefaultMessageFacade());
+    }
+
+    @Override
+    public JmsTextMessage createTextMessage() throws JMSException {
+        return createTextMessage(null);
+    }
+
+    @Override
+    public JmsTextMessage createTextMessage(String payload) throws JMSException {
+
+        // JmsTextMessageFacade facade = new AmqpJmsTextMessageFacade(connection);
+        JmsTextMessageFacade facade = new JmsDefaultTextMessageFacade();
+
+        if (payload != null) {
+            facade.setText(payload);
+        }
+
+        return new JmsTextMessage(facade);
+    }
+
+    @Override
+    public JmsBytesMessage createBytesMessage() throws JMSException {
+        // return new JmsBytesMessage(new AmqpJmsBytesMessageFacade(connection));
+        return new JmsBytesMessage(new JmsDefaultBytesMessageFacade());
+    }
+
+    @Override
+    public JmsMapMessage createMapMessage() throws JMSException {
+        // return new JmsMapMessage(new AmqpJmsMapMessageFacade(connection));
+        return new JmsMapMessage(new JmsDefaultMapMessageFacade());
+    }
+
+    @Override
+    public JmsStreamMessage createStreamMessage() throws JMSException {
+        // return new JmsStreamMessage(new AmqpJmsStreamMessageFacade(connection));
+        return new JmsStreamMessage(new JmsDefaultStreamMessageFacade());
+    }
+
+    @Override
+    public JmsObjectMessage createObjectMessage() throws JMSException {
+        return createObjectMessage(null);
+    }
+
+    @Override
+    public JmsObjectMessage createObjectMessage(Serializable payload) throws JMSException {
+
+        // JmsObjectMessageFacade facade = new AmqpJmsSerializedObjectMessageFacade(connection);
+        JmsObjectMessageFacade facade = new JmsDefaultObjectMessageFacade();
+
+        if (payload != null) {
+            try {
+                facade.setObject(payload);
+            } catch (IOException e) {
+                throw JmsExceptionSupport.create(e);
+            }
+        }
+
+        return new JmsObjectMessage(facade);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessagePropertyIntercepter.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessagePropertyIntercepter.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessagePropertyIntercepter.java
new file mode 100644
index 0000000..11d10a3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsMessagePropertyIntercepter.java
@@ -0,0 +1,377 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_AMQP_REPLY_TO_GROUP_ID;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_AMQP_TTL;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_AMQP_TYPED_ENCODING;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.jms.JMSException;
+import javax.jms.MessageFormatException;
+
+import org.apache.qpid.jms.util.TypeConversionSupport;
+
+/**
+ * Utility class used to intercept calls to Message property sets and gets and map the
+ * correct AMQP fields to the property name being accessed.
+ */
+public class AmqpJmsMessagePropertyIntercepter {
+
+    private static final Map<String, PropertyIntercepter> PROPERTY_INTERCEPTERS = new HashMap<String, PropertyIntercepter>();
+
+    /**
+     * Interface for a Property intercepter object used to write JMS style
+     * properties that are part of the JMS Message object members or perform
+     * some needed conversion action before some named property is read or
+     * written.  If a property is not writable then the intercepter should
+     * throw an JMSException to indicate the error.
+     */
+    interface PropertyIntercepter {
+
+        /**
+         * Called when the names property is queried from an JMS Message object.
+         *
+         * @param message
+         *        The message being acted upon.
+         *
+         * @return the correct property value from the given Message.
+         *
+         * @throws JMSException if an error occurs while accessing the property
+         */
+        Object getProperty(AmqpJmsMessageFacade message) throws JMSException;
+
+        /**
+         * Called when the names property is assigned from an JMS Message object.
+         *
+         * @param message
+         *        The message instance being acted upon.
+         * @param value
+         *        The value to assign to the intercepted property.
+         *
+         * @throws JMSException if an error occurs writing the property.
+         */
+        void setProperty(AmqpJmsMessageFacade message, Object value) throws JMSException;
+
+        /**
+         * Indicates if the intercepted property has a value currently assigned.
+         *
+         * @param message
+         *        The message instance being acted upon.
+         *
+         * @return true if the intercepted property has a value assigned to it.
+         */
+        boolean propertyExists(AmqpJmsMessageFacade message);
+
+    }
+
+    static {
+        PROPERTY_INTERCEPTERS.put(JMS_AMQP_TTL, new PropertyIntercepter() {
+            @Override
+            public Object getProperty(AmqpJmsMessageFacade message) throws JMSException {
+                return message.getAmqpTimeToLive();
+            }
+
+            @Override
+            public void setProperty(AmqpJmsMessageFacade message, Object value) throws JMSException {
+                Long rc = (Long) TypeConversionSupport.convert(value, Long.class);
+                if (rc == null) {
+                    throw new JMSException("Property " + JMS_AMQP_TTL + " cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setAmqpTimeToLive(rc.longValue());
+            }
+
+            @Override
+            public boolean propertyExists(AmqpJmsMessageFacade message) {
+                return message.getAmqpTimeToLive() != 0;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put(JMS_AMQP_REPLY_TO_GROUP_ID, new PropertyIntercepter() {
+            @Override
+            public Object getProperty(AmqpJmsMessageFacade message) throws JMSException {
+                return message.getReplyToGroupId();
+            }
+
+            @Override
+            public void setProperty(AmqpJmsMessageFacade message, Object value) throws JMSException {
+                String rc = (String) TypeConversionSupport.convert(value, String.class);
+                if (rc == null) {
+                    throw new JMSException("Property " + JMS_AMQP_REPLY_TO_GROUP_ID + " cannot be set from a " + value.getClass().getName() + ".");
+                }
+                message.setReplyToGroupId(rc);
+            }
+
+            @Override
+            public boolean propertyExists(AmqpJmsMessageFacade message) {
+                return message.getReplyToGroupId() != null;
+            }
+        });
+        PROPERTY_INTERCEPTERS.put(JMS_AMQP_TYPED_ENCODING, new PropertyIntercepter() {
+            @Override
+            public Object getProperty(AmqpJmsMessageFacade message) throws JMSException {
+                if (message instanceof AmqpJmsObjectMessageFacade) {
+                    return ((AmqpJmsObjectMessageFacade) message).isAmqpTypedEncoding();
+                }
+
+                return false;
+            }
+
+            @Override
+            public void setProperty(AmqpJmsMessageFacade message, Object value) throws JMSException {
+                Integer rc = (Integer) TypeConversionSupport.convert(value, Boolean.class);
+                if (rc == null) {
+                    throw new JMSException("Property " + JMS_AMQP_TYPED_ENCODING + " cannot be set from a " + value.getClass().getName() + ".");
+                }
+
+                // TODO - Finished Typed encoding work.
+                if (message instanceof AmqpJmsObjectMessageFacade) {
+                    // ((AmqpJmsSerializedObjectMessageFacade) message)
+                } else {
+                    throw new MessageFormatException(JMS_AMQP_TYPED_ENCODING + " is only applicable to ObjectMessage");
+                }
+            }
+
+            @Override
+            public boolean propertyExists(AmqpJmsMessageFacade message) {
+                if (message instanceof AmqpJmsObjectMessageFacade) {
+                    // TODO - See notes in AmqpObjectMessageFacade about whether this should
+                    //        always be exposed for ObjectMessage or only if it's currently
+                    //        the case that the message uses the AMQP typed encoding.
+                    return ((AmqpJmsObjectMessageFacade) message).isAmqpTypedEncoding();
+                }
+
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Static get method that takes a property name and gets the value either via
+     * a registered property get object or through the AmqpJmsMessageFacade getProperty
+     * method.
+     *
+     * @param message
+     *        the AmqpJmsMessageFacade instance to read from
+     * @param name
+     *        the property name that is being requested.
+     *
+     * @return the correct value either mapped to an attribute of a Message or a message property.
+     *
+     * @throws JMSException if an error occurs while reading the defined property.
+     */
+    public static Object getProperty(AmqpJmsMessageFacade message, String name) throws JMSException {
+        Object value = null;
+
+        PropertyIntercepter propertyExpression = PROPERTY_INTERCEPTERS.get(name);
+        if (propertyExpression != null) {
+            value = propertyExpression.getProperty(message);
+        } else {
+            value = message.getApplicationProperty(name);
+        }
+
+        return value;
+    }
+
+    /**
+     * Static set method that takes a property name and sets the value either via
+     * a registered property set object or through the AmqpJmsMessageFacade setProperty
+     * method.
+     *
+     * @param message
+     *        the AmqpJmsMessageFacade instance to write to.
+     * @param name
+     *        the property name that is being written.
+     * @param value
+     *        the new value to assign for the named property.
+     *
+     * @throws JMSException if an error occurs while writing the defined property.
+     */
+    public static void setProperty(AmqpJmsMessageFacade message, String name, Object value) throws JMSException {
+        PropertyIntercepter propertyExpression = PROPERTY_INTERCEPTERS.get(name);
+        if (propertyExpression != null) {
+            propertyExpression.setProperty(message, value);
+        } else {
+            message.setApplicationProperty(name, value);
+        }
+    }
+
+    /**
+     * Static query method to determine if a specific property exists in the given message.
+     *
+     * @param message
+     *        the AmqpJmsMessageFacade instance to write to.
+     * @param name
+     *        the property name that is being checked.
+     *
+     * @throws JMSException if an error occurs while inspecting the defined property.
+     */
+    public static void propertyExists(AmqpJmsMessageFacade message, String name) throws JMSException {
+        PropertyIntercepter propertyExpression = PROPERTY_INTERCEPTERS.get(name);
+        if (propertyExpression != null) {
+            propertyExpression.propertyExists(message);
+        } else {
+            message.applicationPropertyExists(name);
+        }
+    }
+
+    /**
+     * For each of the currently configured message property intercepter instance a
+     * string key value is inserted into an Set and returned.
+     *
+     * @return a Set<String> containing the names of all intercepted properties.
+     */
+    public static Set<String> getAllPropertyNames() {
+        return PROPERTY_INTERCEPTERS.keySet();
+    }
+
+    /**
+     * For each of the currently configured message property intercepter instance a
+     * string key value is inserted into an Set and returned if the property has a
+     * value and is available for a read operation.
+     *
+     * @return a Set<String> containing the names of all intercepted properties with a value.
+     */
+    public static Set<String> getPropertyNames(AmqpJmsMessageFacade message) {
+        Set<String> names = new HashSet<String>();
+        for (Entry<String, PropertyIntercepter> entry : PROPERTY_INTERCEPTERS.entrySet()) {
+            if (entry.getValue().propertyExists(message)) {
+                names.add(entry.getKey());
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Allows for the additional PropertyIntercepter instances to be added to the global set.
+     *
+     * @param propertyName
+     *        The name of the Message property that will be intercepted.
+     * @param getter
+     *        The PropertyIntercepter instance that should be used for the named property.
+     */
+    public static void addPropertyIntercepter(String propertyName, PropertyIntercepter getter) {
+        PROPERTY_INTERCEPTERS.put(propertyName, getter);
+    }
+
+    /**
+     * Given a property name, remove the configured intercepter that has been assigned to
+     * intercept calls for that property value.
+     *
+     * @param propertyName
+     *        The name of the PropertyIntercepter to remove.
+     *
+     * @return true if a getter was removed from the global set.
+     */
+    public boolean removePropertyIntercepter(String propertyName) {
+        if (PROPERTY_INTERCEPTERS.remove(propertyName) != null) {
+            return true;
+        }
+
+        return false;
+    }
+
+    private final String name;
+    private final PropertyIntercepter propertyExpression;
+
+    /**
+     * Creates an new property getter instance that is assigned to read the named value.
+     *
+     * @param name
+     *        the property value that this getter is assigned to lookup.
+     */
+    public AmqpJmsMessagePropertyIntercepter(String name) {
+        this.name = name;
+        this.propertyExpression = PROPERTY_INTERCEPTERS.get(name);
+    }
+
+    /**
+     * Gets the correct property value from the JmsMessageFacade instance based on
+     * the predefined property mappings.
+     *
+     * @param message
+     *        the JmsMessageFacade whose property is being read.
+     *
+     * @return the correct value either mapped to an Message attribute of a Message property.
+     *
+     * @throws JMSException if an error occurs while reading the defined property.
+     */
+    public Object get(AmqpJmsMessageFacade message) throws JMSException {
+        if (propertyExpression != null) {
+            return propertyExpression.getProperty(message);
+        }
+
+        return message.getApplicationProperty(name);
+    }
+
+    /**
+     * Sets the correct property value from the AmqpJmsMessageFacade instance based on
+     * the predefined property mappings.
+     *
+     * @param message
+     *        the AmqpJmsMessageFacade whose property is being read.
+     * @param value
+     *        the value to be set on the intercepted AmqpJmsMessageFacade property.
+     *
+     * @throws JMSException if an error occurs while reading the defined property.
+     */
+    public void set(AmqpJmsMessageFacade message, Object value) throws JMSException {
+        if (propertyExpression != null) {
+            propertyExpression.setProperty(message, value);
+        } else {
+            message.setApplicationProperty(name, value);
+        }
+    }
+
+    /**
+     * @return the property name that is being intercepted for the AmqpJmsMessageFacade.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !this.getClass().equals(o.getClass())) {
+            return false;
+        }
+        return name.equals(((AmqpJmsMessagePropertyIntercepter) o).name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
new file mode 100644
index 0000000..3696653
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsObjectMessageFacade.java
@@ -0,0 +1,124 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_OBJECT_MESSAGE;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Wrapper around an AMQP Message instance that will be treated as a JMS ObjectMessage
+ * type.
+ */
+public class AmqpJmsObjectMessageFacade extends AmqpJmsMessageFacade implements JmsObjectMessageFacade {
+
+    private AmqpObjectTypeDelegate delegate;
+
+    /**
+     * @param connection
+     */
+    public AmqpJmsObjectMessageFacade(AmqpConnection connection) {
+        super(connection);
+        setAnnotation(JMS_MSG_TYPE, JMS_OBJECT_MESSAGE);
+
+        // TODO Implement Connection property to control default serialization type
+        initDelegate(false);
+    }
+
+    /**
+     * @param connection
+     * @param message
+     */
+    public AmqpJmsObjectMessageFacade(AmqpConnection connection, Message message) {
+        super(connection, message);
+
+        // TODO detect the content type and init the proper delegate.
+        initDelegate(false);
+    }
+
+    /**
+     * @return the appropriate byte value that indicates the type of message this is.
+     */
+    @Override
+    public byte getJmsMsgType() {
+        return JMS_OBJECT_MESSAGE;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        // TODO - If null body changes to empty AmqpValue this needs to also change.
+        return getAmqpMessage().getBody() == null;
+    }
+
+    public boolean isAmqpTypedEncoding() {
+        return this.delegate instanceof AmqpObjectTypeDelegate;
+    }
+
+    @Override
+    public JmsObjectMessageFacade copy() throws JMSException {
+        AmqpJmsObjectMessageFacade copy = new AmqpJmsObjectMessageFacade(connection);
+        copyInto(copy);
+
+        try {
+            copy.setObject(getObject());
+        } catch (Exception e) {
+            throw JmsExceptionSupport.create("Failed to copy object value", e);
+        }
+
+        return copy;
+    }
+
+    @Override
+    public Serializable getObject() throws IOException, ClassNotFoundException {
+        return delegate.getObject();
+    }
+
+    @Override
+    public void setObject(Serializable value) throws IOException {
+        delegate.setObject(value);
+    }
+
+    @Override
+    public void clearBody() {
+        try {
+            setObject(null);
+        } catch (IOException e) {
+        }
+    }
+
+    @Override
+    public void onSend() {
+        // TODO instruct delegate to encode the proper content type into the message.
+    }
+
+    private void initDelegate(boolean useAmqpTypes) {
+        if (!useAmqpTypes) {
+            delegate = new AmqpSerializedObjectDelegate(getAmqpMessage());
+        } else {
+            delegate = new AmqpTypedObjectDelegate(getAmqpMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsStreamMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsStreamMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsStreamMessageFacade.java
new file mode 100644
index 0000000..0999225
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsStreamMessageFacade.java
@@ -0,0 +1,163 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_STREAM_MESSAGE;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.jms.MessageEOFException;
+
+import org.apache.qpid.jms.message.facade.JmsStreamMessageFacade;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Wrapper around an AMQP Message instance that will be treated as a JMS StreamMessage
+ * type.
+ */
+public class AmqpJmsStreamMessageFacade extends AmqpJmsMessageFacade implements JmsStreamMessageFacade {
+
+    private List<Object> list;
+    private int position = 0;
+
+    /**
+     * Create a new facade ready for sending.
+     *
+     * @param connection
+     *        the connection instance that created this facade.
+     */
+    public AmqpJmsStreamMessageFacade(AmqpConnection connection) {
+        super(connection);
+        initializeEmptyList();
+        setAnnotation(JMS_MSG_TYPE, JMS_STREAM_MESSAGE);
+    }
+
+    /**
+     * Creates a new Facade around an incoming AMQP Message for dispatch to the
+     * JMS Consumer instance.
+     *
+     * @param connection
+     *        the connection that created this Facade.
+     * @param message
+     *        the incoming Message instance that is being wrapped.
+     */
+    @SuppressWarnings("unchecked")
+    public AmqpJmsStreamMessageFacade(AmqpConnection connection, Message message) {
+        super(connection, message);
+
+        Section body = getAmqpMessage().getBody();
+        if (body == null) {
+            initializeEmptyList();
+        } else if (body instanceof AmqpValue) {
+            Object value = ((AmqpValue) body).getValue();
+
+            if (value == null) {
+                initializeEmptyList();
+            } else if (value instanceof List) {
+                list = (List<Object>) value;
+            } else {
+                throw new IllegalStateException("Unexpected amqp-value body content type: " + value.getClass().getSimpleName());
+            }
+        } else {
+            throw new IllegalStateException("Unexpected message body type: " + body.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public JmsStreamMessageFacade copy() {
+        AmqpJmsStreamMessageFacade copy = new AmqpJmsStreamMessageFacade(connection);
+        copyInto(copy);
+        copy.list.addAll(list);
+        return copy;
+    }
+
+    /**
+     * @return the appropriate byte value that indicates the type of message this is.
+     */
+    @Override
+    public byte getJmsMsgType() {
+        return JMS_STREAM_MESSAGE;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return !list.isEmpty() && position < list.size();
+    }
+
+    @Override
+    public Object peek() throws MessageEOFException {
+        if (list.isEmpty() || position >= list.size()) {
+            throw new MessageEOFException("Attempt to read past end of stream");
+        }
+
+        Object object = list.get(position);
+        if (object instanceof Binary) {
+            // Copy to a byte[], ensure we copy only the required portion.
+            Binary bin = ((Binary) object);
+            object = Arrays.copyOfRange(bin.getArray(), bin.getArrayOffset(), bin.getLength());
+        }
+
+        return object;
+    }
+
+    @Override
+    public void pop() throws MessageEOFException {
+        if (list.isEmpty() || position >= list.size()) {
+            throw new MessageEOFException("Attempt to read past end of stream");
+        }
+
+        position++;
+    }
+
+    @Override
+    public void put(Object value) {
+        Object entry = value;
+        if (entry instanceof byte[]) {
+            entry = new Binary((byte[]) value);
+        }
+
+        list.add(entry);
+    }
+
+    @Override
+    public void reset() {
+        position = 0;
+    }
+
+    @Override
+    public void clearBody() {
+        list.clear();
+        position = 0;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return list.isEmpty();
+    }
+
+    private void initializeEmptyList() {
+        List<Object> list = new ArrayList<Object>();
+        message.setBody(new AmqpValue(list));
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsTextMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsTextMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsTextMessageFacade.java
new file mode 100644
index 0000000..6c2421b
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpJmsTextMessageFacade.java
@@ -0,0 +1,156 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_MSG_TYPE;
+import static org.apache.qpid.jms.provider.amqp.message.AmqpMessageSupport.JMS_TEXT_MESSAGE;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.facade.JmsTextMessageFacade;
+import org.apache.qpid.jms.provider.amqp.AmqpConnection;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.AmqpValue;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Wrapper around an AMQP Message instance that will be treated as a JMS TextMessage
+ * type.
+ */
+public class AmqpJmsTextMessageFacade extends AmqpJmsMessageFacade implements JmsTextMessageFacade {
+
+    private static final String UTF_8 = "UTF-8";
+
+    /**
+     * Content type, only to be used when message uses a data
+     * body section, and not when using an amqp-value body section
+     */
+    public static final String CONTENT_TYPE = "text/plain";
+
+    private final CharsetDecoder decoder =  Charset.forName(UTF_8).newDecoder();
+
+    /**
+     * Create a new AMQP Message facade ready for sending.
+     *
+     * @param connection
+     *        The AMQP Connection that created this message.
+     */
+    public AmqpJmsTextMessageFacade(AmqpConnection connection) {
+        super(connection);
+        setAnnotation(JMS_MSG_TYPE, JMS_TEXT_MESSAGE);
+        setText(null);
+    }
+
+    /**
+     * Creates a new Facade around an incoming AMQP Message for dispatch to the
+     * JMS Consumer instance.
+     *
+     * @param connection
+     *        the connection that created this Facade.
+     * @param message
+     *        the incoming Message instance that is being wrapped.
+     */
+    public AmqpJmsTextMessageFacade(AmqpConnection connection, Message message) {
+        super(connection, message);
+    }
+
+    /**
+     * @return the appropriate byte value that indicates the type of message this is.
+     */
+    @Override
+    public byte getJmsMsgType() {
+        return JMS_TEXT_MESSAGE;
+    }
+
+    @Override
+    public JmsTextMessageFacade copy() throws JMSException {
+        AmqpJmsTextMessageFacade copy = new AmqpJmsTextMessageFacade(connection);
+        copyInto(copy);
+        copy.setText(getText());
+        return copy;
+    }
+
+    @Override
+    public String getText() throws JMSException {
+        Section body = getAmqpMessage().getBody();
+
+        if (body == null) {
+            return null;
+        } else if (body instanceof Data) {
+            Data data = (Data) body;
+            if (data.getValue() == null || data.getValue().getLength() == 0) {
+                return "";
+            } else {
+                Binary b = data.getValue();
+                ByteBuffer buf = ByteBuffer.wrap(b.getArray(), b.getArrayOffset(), b.getLength());
+
+                try {
+                    CharBuffer chars = decoder.decode(buf);
+                    return String.valueOf(chars);
+                } catch (CharacterCodingException e) {
+                    throw JmsExceptionSupport.create("Cannot decode String in UFT-8", e);
+                }
+            }
+        } else if (body instanceof AmqpValue) {
+            Object value = ((AmqpValue) body).getValue();
+
+            if (value == null || value instanceof String) {
+                return (String) value;
+            } else {
+                throw new IllegalStateException("Unexpected amqp-value body content type: " + value.getClass().getSimpleName());
+            }
+        } else {
+            throw new IllegalStateException("Unexpected message body type: " + body.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public void setText(String value) {
+        AmqpValue body = new AmqpValue(value);
+        getAmqpMessage().setBody(body);
+    }
+
+    @Override
+    public void clearBody() {
+        setText(null);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        Section body = getAmqpMessage().getBody();
+
+        if (body == null) {
+            return true;
+        } else if (body instanceof Data) {
+            Data data = (Data) body;
+            if (data.getValue() == null || data.getValue().getLength() == 0) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelper.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelper.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelper.java
new file mode 100644
index 0000000..0bda795
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageIdHelper.java
@@ -0,0 +1,270 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.jms.provider.amqp.message;
+
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import org.apache.qpid.jms.exceptions.IdConversionException;
+
+/**
+ * Helper class for identifying and converting message-id and correlation-id values between
+ * the AMQP types and the Strings values used by JMS.
+ *
+ * <p>AMQP messages allow for 4 types of message-id/correlation-id: message-id-string, message-id-binary,
+ * message-id-uuid, or message-id-ulong. In order to accept or return a string representation of these
+ * for interoperability with other AMQP clients, the following encoding can be used after removing or
+ * before adding the "ID:" prefix used for a JMSMessageID value<br/>
+ *
+ * "AMQP_BINARY:&lt;hex representation of binary content&gt;"<br/>
+ * "AMQP_UUID:&lt;string representation of uuid&gt;"<br/>
+ * "AMQP_ULONG:&lt;string representation of ulong&gt;"<br/>
+ * "AMQP_STRING:&lt;string&gt;"<br/>
+ *
+ * <p>The AMQP_STRING encoding exists only for escaping message-id-string values that happen to begin
+ * with one of the encoding prefixes (including AMQP_STRING itself). It MUST NOT be used otherwise.
+ *
+ * <p>When provided a string for conversion which attempts to identify itself as an encoded binary, uuid, or
+ * ulong but can't be converted into the indicated format, an exception will be thrown.
+ *
+ */
+public class AmqpMessageIdHelper {
+    public static final String AMQP_STRING_PREFIX = "AMQP_STRING:";
+    public static final String AMQP_UUID_PREFIX = "AMQP_UUID:";
+    public static final String AMQP_ULONG_PREFIX = "AMQP_ULONG:";
+    public static final String AMQP_BINARY_PREFIX = "AMQP_BINARY:";
+    public static final String JMS_ID_PREFIX = "ID:";
+
+    private static final int JMS_ID_PREFIX_LENGTH = JMS_ID_PREFIX.length();
+    private static final int AMQP_UUID_PREFIX_LENGTH = AMQP_UUID_PREFIX.length();
+    private static final int AMQP_ULONG_PREFIX_LENGTH = AMQP_ULONG_PREFIX.length();
+    private static final int AMQP_STRING_PREFIX_LENGTH = AMQP_STRING_PREFIX.length();
+    private static final int AMQP_BINARY_PREFIX_LENGTH = AMQP_BINARY_PREFIX.length();
+    private static final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
+
+    /**
+     * Checks whether the given string begins with "ID:" prefix used to denote a JMSMessageID
+     *
+     * @param string the string to check
+     * @return true if and only id the string begins with "ID:"
+     */
+    public boolean hasMessageIdPrefix(String string) {
+        if (string == null) {
+            return false;
+        }
+
+        return string.startsWith(JMS_ID_PREFIX);
+    }
+
+    /**
+     * Returns the suffix of the given string after removing the first "ID:" prefix (if present).
+     *
+     * @param string the string to process
+     * @return the suffix, or the original String if the "ID:" prefix is not present
+     */
+    public String stripMessageIdPrefix(String id) {
+        if (hasMessageIdPrefix(id)) {
+            return strip(id, JMS_ID_PREFIX_LENGTH);
+        } else {
+            return id;
+        }
+    }
+
+    private String strip(String id, int numChars) {
+        return id.substring(numChars);
+    }
+
+    /**
+     * Takes the provided amqp messageId style object, and convert it to a base string.
+     * Encodes type information as a prefix where necessary to convey or escape the type
+     * of the provided object.
+     *
+     * @param messageId the object to process
+     * @return the base string to be used in creating the actual JMS id.
+     */
+    public String toBaseMessageIdString(Object messageId) {
+        if (messageId == null) {
+            return null;
+        } else if (messageId instanceof String) {
+            String stringId = (String) messageId;
+
+            // If the given string has a type encoding prefix,
+            // we need to escape it as an encoded string (even if
+            // the existing encoding prefix was also for string)
+            if (hasTypeEncodingPrefix(stringId)) {
+                return AMQP_STRING_PREFIX + stringId;
+            } else {
+                return stringId;
+            }
+        } else if (messageId instanceof UUID) {
+            return AMQP_UUID_PREFIX + messageId.toString();
+        } else if (messageId instanceof BigInteger || messageId instanceof Long) {
+            return AMQP_ULONG_PREFIX + messageId.toString();
+        } else if (messageId instanceof ByteBuffer) {
+            ByteBuffer dup = ((ByteBuffer) messageId).duplicate();
+
+            byte[] bytes = new byte[dup.remaining()];
+            dup.get(bytes);
+
+            String hex = convertBinaryToHexString(bytes);
+
+            return AMQP_BINARY_PREFIX + hex;
+        } else {
+            throw new IllegalArgumentException("Unsupported type provided: " + messageId.getClass());
+        }
+    }
+
+    private boolean hasTypeEncodingPrefix(String stringId) {
+        return hasAmqpBinaryPrefix(stringId) ||
+                    hasAmqpUuidPrefix(stringId) ||
+                        hasAmqpUlongPrefix(stringId) ||
+                            hasAmqpStringPrefix(stringId);
+    }
+
+    private boolean hasAmqpStringPrefix(String stringId) {
+        return stringId.startsWith(AMQP_STRING_PREFIX);
+    }
+
+    private boolean hasAmqpUlongPrefix(String stringId) {
+        return stringId.startsWith(AMQP_ULONG_PREFIX);
+    }
+
+    private boolean hasAmqpUuidPrefix(String stringId) {
+        return stringId.startsWith(AMQP_UUID_PREFIX);
+    }
+
+    private boolean hasAmqpBinaryPrefix(String stringId) {
+        return stringId.startsWith(AMQP_BINARY_PREFIX);
+    }
+
+    /**
+     * Takes the provided base id string and return the appropriate amqp messageId style object.
+     * Converts the type based on any relevant encoding information found as a prefix.
+     *
+     * @param baseId the object to be converted
+     * @return the amqp messageId style object
+     * @throws IdConversionException if the provided baseId String indicates an encoded type but can't be converted to that type. 
+     */
+    public Object toIdObject(String baseId) throws IdConversionException {
+        if (baseId == null) {
+            return null;
+        }
+
+        try {
+            if (hasAmqpUuidPrefix(baseId)) {
+                String uuidString = strip(baseId, AMQP_UUID_PREFIX_LENGTH);
+                return UUID.fromString(uuidString);
+            } else if (hasAmqpUlongPrefix(baseId)) {
+                String longString = strip(baseId, AMQP_ULONG_PREFIX_LENGTH);
+                return new BigInteger(longString);
+            } else if (hasAmqpStringPrefix(baseId)) {
+                return strip(baseId, AMQP_STRING_PREFIX_LENGTH);
+            } else if (hasAmqpBinaryPrefix(baseId)) {
+                String hexString = strip(baseId, AMQP_BINARY_PREFIX_LENGTH);
+                byte[] bytes = convertHexStringToBinary(hexString);
+                return ByteBuffer.wrap(bytes);
+            } else {
+                // We have a string without any type prefix, transmit it as-is.
+                return baseId;
+            }
+        } catch (IllegalArgumentException e) {
+            throw new IdConversionException("Unable to convert ID value", e);
+        }
+    }
+
+    /**
+     * Convert the provided hex-string into a binary representation where each byte represents
+     * two characters of the hex string.
+     *
+     * The hex characters may be upper or lower case.
+     *
+     * @param hexString string to convert
+     * @return a byte array containing the binary representation
+     * @throws IllegalArgumentException if the provided String is a non-even length or contains non-hex characters
+     */
+    public byte[] convertHexStringToBinary(String hexString) throws IllegalArgumentException {
+        int length = hexString.length();
+
+        // As each byte needs two characters in the hex encoding, the string must be an even length.
+        if (length % 2 != 0) {
+            throw new IllegalArgumentException("The provided hex String must be an even length, but was of length " + length + ": " + hexString);
+        }
+
+        byte[] binary = new byte[length / 2];
+
+        for (int i = 0; i < length; i += 2) {
+            char highBitsChar = hexString.charAt(i);
+            char lowBitsChar = hexString.charAt(i + 1);
+
+            int highBits = hexCharToInt(highBitsChar, hexString) << 4;
+            int lowBits = hexCharToInt(lowBitsChar, hexString);
+
+            binary[i / 2] = (byte) (highBits + lowBits);
+        }
+
+        return binary;
+    }
+
+    private int hexCharToInt(char ch, String orig) throws IllegalArgumentException {
+        if (ch >= '0' && ch <= '9') {
+            // subtract '0' to get difference in position as an int
+            return ch - '0';
+        } else if (ch >= 'A' && ch <= 'F') {
+            // subtract 'A' to get difference in position as an int
+            // and then add 10 for the offset of 'A'
+            return ch - 'A' + 10;
+        } else if (ch >= 'a' && ch <= 'f') {
+            // subtract 'a' to get difference in position as an int
+            // and then add 10 for the offset of 'a'
+            return ch - 'a' + 10;
+        }
+
+        throw new IllegalArgumentException("The provided hex string contains non-hex character '" + ch + "': " + orig);
+    }
+
+    /**
+     * Convert the provided binary into a hex-string representation where each character
+     * represents 4 bits of the provided binary, i.e each byte requires two characters.
+     *
+     * The returned hex characters are upper-case.
+     *
+     * @param bytes binary to convert
+     * @return a String containing a hex representation of the bytes
+     */
+    public String convertBinaryToHexString(byte[] bytes) {
+        // Each byte is represented as 2 chars
+        StringBuilder builder = new StringBuilder(bytes.length * 2);
+
+        for (byte b : bytes) {
+            // The byte will be expanded to int before shifting, replicating the
+            // sign bit, so mask everything beyond the first 4 bits afterwards
+            int highBitsInt = (b >> 4) & 0xF;
+            // We only want the first 4 bits
+            int lowBitsInt = b & 0xF;
+
+            builder.append(HEX_CHARS[highBitsInt]);
+            builder.append(HEX_CHARS[lowBitsInt]);
+        }
+
+        return builder.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageSupport.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageSupport.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageSupport.java
new file mode 100644
index 0000000..a01d415
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpMessageSupport.java
@@ -0,0 +1,169 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import javax.jms.Destination;
+import javax.jms.Queue;
+import javax.jms.TemporaryQueue;
+import javax.jms.TemporaryTopic;
+import javax.jms.Topic;
+
+import org.apache.qpid.proton.amqp.Symbol;
+
+/**
+ * Support class containing constant values and static methods that are
+ * used to map to / from AMQP Message types being sent or received.
+ */
+public final class AmqpMessageSupport {
+
+    /**
+     * The Annotation name to store the destination name that the Message
+     * will be sent to.  The Message should also be tagged with the appropriate
+     * destination attribute to allow the receiver to determine the correct
+     * destination type.
+     */
+    public static final String AMQP_TO_ANNOTATION = "x-opt-to-type";
+
+    /**
+     * The Annotation name to store the destination name that the sender wants
+     * to receive replies on.  The Message should also be tagged with the
+     * appropriate destination attribute to allow the receiver to determine the
+     * correct destination type.
+     */
+    public static final String AMQP_REPLY_TO_ANNOTATION = "x-opt-reply-type";
+
+    /**
+     * Attribute used to mark a destination as temporary.
+     */
+    public static final String TEMPORARY_ATTRIBUTE = "temporary";
+
+    /**
+     * Attribute used to mark a destination as being a Queue type.
+     */
+    public static final String QUEUE_ATTRIBUTES = "queue";
+
+    /**
+     * Attribute used to mark a destination as being a Topic type.
+     */
+    public static final String TOPIC_ATTRIBUTES = "topic";
+
+    /**
+     * Convenience value used to mark a destination as a Temporary Queue.
+     */
+    public static final String TEMP_QUEUE_ATTRIBUTES = TEMPORARY_ATTRIBUTE + "," + QUEUE_ATTRIBUTES;
+
+    /**
+     * Convenience value used to mark a destination as a Temporary Topic.
+     */
+    public static final String TEMP_TOPIC_ATTRIBUTES = TEMPORARY_ATTRIBUTE + "," + TOPIC_ATTRIBUTES;
+
+    /**
+     * Attribute used to mark the Application defined correlation Id that has been
+     * set for the message.
+     */
+    public static final String JMS_APP_CORRELATION_ID = "x-opt-app-correlation-id";
+
+    /**
+     * Attribute used to mark the JMSType value set on the message.
+     */
+    public static final String JMS_TYPE = "x-opt-jms-type";
+
+    /**
+     * Attribute used to mark the JMS Type that the message instance represents.
+     */
+    public static final String JMS_MSG_TYPE = "x-opt-jms-msg-type";
+
+    /**
+     * Value mapping for JMS_MSG_TYPE which indicates the message is a generic JMS Message
+     * which has no body.
+     */
+    public static final byte JMS_MESSAGE = 0;
+
+    /**
+     * Value mapping for JMS_MSG_TYPE which indicates the message is a JMS ObjectMessage
+     * which has an Object value serialized in its message body.
+     */
+    public static final byte JMS_OBJECT_MESSAGE = 1;
+
+    /**
+     * Value mapping for JMS_MSG_TYPE which indicates the message is a JMS MapMessage
+     * which has an Map instance serialized in its message body.
+     */
+    public static final byte JMS_MAP_MESSAGE = 2;
+
+    /**
+     * Value mapping for JMS_MSG_TYPE which indicates the message is a JMS BytesMessage
+     * which has a body that consists of raw bytes.
+     */
+    public static final byte JMS_BYTES_MESSAGE = 3;
+
+    /**
+     * Value mapping for JMS_MSG_TYPE which indicates the message is a JMS StreamMessage
+     * which has a body that is a structured collection of primitives values.
+     */
+    public static final byte JMS_STREAM_MESSAGE = 4;
+
+    /**
+     * Value mapping for JMS_MSG_TYPE which indicates the message is a JMS TextMessage
+     * which has a body that contains a UTF-8 encoded String.
+     */
+    public static final byte JMS_TEXT_MESSAGE = 5;
+
+    public static final String JMS_AMQP_TTL = "JMS_AMQP_TTL";
+    public static final String JMS_AMQP_REPLY_TO_GROUP_ID = "JMS_AMQP_REPLY_TO_GROUP_ID";
+    public static final String JMS_AMQP_TYPED_ENCODING = "JMS_AMQP_TYPED_ENCODING";
+
+    /**
+     * Lookup and return the correct Proton Symbol instance based on the given key.
+     *
+     * @param key
+     *        the String value name of the Symbol to locate.
+     *
+     * @return the Symbol value that matches the given key.
+     */
+    public static Symbol getSymbol(String key) {
+        return Symbol.valueOf(key);
+    }
+
+    /**
+     * Given a JMS Destination object return the correct message annotations that
+     * will identify the type of Destination the name represents, Queue. Topic, etc.
+     *
+     * @param destination
+     *        The JMS Destination to be examined.
+     *
+     * @return the correct message annotation values to describe the given Destination.
+     */
+    public static String destinationAttributes(Destination destination) {
+        if (destination instanceof Queue) {
+            if (destination instanceof TemporaryQueue) {
+                return TEMP_QUEUE_ATTRIBUTES;
+            } else {
+                return QUEUE_ATTRIBUTES;
+            }
+        }
+        if (destination instanceof Topic) {
+            if (destination instanceof TemporaryTopic) {
+                return TEMP_TOPIC_ATTRIBUTES;
+            } else {
+                return TOPIC_ATTRIBUTES;
+            }
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
new file mode 100644
index 0000000..cfa6237
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpObjectTypeDelegate.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.qpid.jms.provider.amqp.message;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+/**
+ * Interface for a Delegate object that handles storing and retrieving the Object
+ * value in an Object message.
+ */
+public interface AmqpObjectTypeDelegate {
+
+    /**
+     * Given a serializable instance, store the value into the AMQP message using
+     * the strategy implemented by this delegate.
+     *
+     * @param value
+     *        A serializable object instance to be stored in the message.
+     *
+     * @throws IOException if an error occurs during the store operation.
+     */
+    void setObject(Serializable value) throws IOException;
+
+    /**
+     * Read a Serialized object from the AMQP message using the strategy implemented
+     * by this delegate.
+     *
+     * @return an Object that has been read from the stored object data in the message.
+     *
+     * @throws IOException if an error occurs while reading the stored object.
+     * @throws ClassNotFoundException if no class can be found for the stored type.
+     */
+    Serializable getObject() throws IOException, ClassNotFoundException;
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
new file mode 100644
index 0000000..72db9dc
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/message/AmqpSerializedObjectDelegate.java
@@ -0,0 +1,101 @@
+/**
+ * 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.jms.provider.amqp.message;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.messaging.Data;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.Message;
+
+/**
+ * Wrapper around an AMQP Message instance that will be treated as a JMS ObjectMessage
+ * type.
+ */
+public class AmqpSerializedObjectDelegate implements AmqpObjectTypeDelegate {
+
+    public static final String CONTENT_TYPE = "application/x-java-serialized-object";
+
+    private final Message message;
+
+    /**
+     * Create a new delegate that uses Java serialization to store the message content.
+     *
+     * @param message
+     *        the AMQP message instance where the object is to be stored / read.
+     */
+    public AmqpSerializedObjectDelegate(Message message) {
+        this.message = message;
+        this.message.setContentType(CONTENT_TYPE);
+    }
+
+    @Override
+    public Serializable getObject() throws IOException, ClassNotFoundException {
+        Binary bin = null;
+
+        Section body = message.getBody();
+        if (body == null) {
+            return null;
+        } else if (body instanceof Data) {
+            bin = ((Data) body).getValue();
+        } else {
+            throw new IllegalStateException("Unexpected body type: " + body.getClass().getSimpleName());
+        }
+
+        if (bin == null) {
+            return null;
+        } else {
+            Serializable serialized = null;
+
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bin.getArray(), bin.getArrayOffset(), bin.getLength());
+                 ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(bais)) {
+
+                serialized = (Serializable) objIn.readObject();
+            }
+
+            return serialized;
+        }
+    }
+
+    @Override
+    public void setObject(Serializable value) throws IOException {
+        if(value == null) {
+            // TODO: verify whether not sending a body is ok,
+            //       send a serialized null instead if it isn't
+            message.setBody(null);
+        } else {
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+
+               oos.writeObject(value);
+               oos.flush();
+               oos.close();
+
+               byte[] bytes = baos.toByteArray();
+               message.setBody(new Data(new Binary(bytes)));
+            }
+        }
+
+        // TODO: ensure content type is [still] set?
+    }
+}


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


[21/27] Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsBytesMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsBytesMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsBytesMessageFacade.java
new file mode 100644
index 0000000..b2428eb
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsBytesMessageFacade.java
@@ -0,0 +1,54 @@
+/**
+ * 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.jms.message.facade;
+
+import javax.jms.JMSException;
+
+import org.fusesource.hawtbuf.Buffer;
+
+/**
+ * Interface for a Message Facade that wraps a BytesMessage based message
+ * instance.
+ */
+public interface JmsBytesMessageFacade extends JmsMessageFacade {
+
+    /**
+     * @returns a deep copy of this Message Facade including a complete copy
+     * of the byte contents of the wrapped message.
+     */
+    @Override
+    JmsBytesMessageFacade copy() throws JMSException;
+
+    /**
+     * Retrieves the contents of this message either wrapped in or copied
+     * into a Buffer instance.  If the message contents are empty a null
+     * Buffer instance may be returned.
+     *
+     * @returns a new Buffer that contains the contents of this message.
+     */
+    Buffer getContent();
+
+    /**
+     * Sets the contents of the message to the new value based on the bytes
+     * stored in the passed in Buffer.
+     *
+     * @param contents
+     *        the new bytes to store in this message.
+     */
+    void setContent(Buffer content);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMapMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMapMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMapMessageFacade.java
new file mode 100644
index 0000000..6ef28c4
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMapMessageFacade.java
@@ -0,0 +1,90 @@
+/**
+ * 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.jms.message.facade;
+
+import java.util.Enumeration;
+
+import javax.jms.JMSException;
+
+/**
+ * Interface for a message Facade that wraps a MapMessage style provider
+ * message.
+ */
+public interface JmsMapMessageFacade extends JmsMessageFacade {
+
+    /**
+     * @returns a deep copy of this Message Facade including a complete copy
+     * of the byte contents of the wrapped message.
+     *
+     * @throws JMSException if an error occurs while copying this message.
+     */
+    @Override
+    JmsMapMessageFacade copy() throws JMSException;
+
+    /**
+     * Returns an Enumeration of all the names in the MapMessage object.
+     *
+     * @return an enumeration of all the names in this MapMessage
+     */
+    Enumeration<String> getMapNames();
+
+    /**
+     * Determines whether an item exists in this Map based message.
+     *
+     * @returns true if the item exists in the Map, false otherwise.
+     */
+    boolean itemExists(String key);
+
+    /**
+     * Gets the value stored in the Map at the specified key.
+     *
+     * @param key
+     *        the key to use to access a value in the Map.
+     *
+     * @returns the item associated with the given key, or null if not present.
+     */
+    Object get(String key);
+
+    /**
+     * Sets an object value with the specified name into the Map.
+     *
+     * If a previous mapping for the key exists, the old value is replaced by the
+     * specified value.
+     *
+     * If the value provided is a byte[] its entry then it is assumed that it was
+     * copied by the caller and its value will not be altered by the provider.
+     *
+     * @param key
+     *        the key to use to store the value into the Map.
+     * @param value
+     *        the new value to store in the element defined by the key.
+     */
+    void put(String key, Object value);
+
+    /**
+     * Remove the mapping for this key from the map if present.  If the value is not
+     * present in the map then this method should return without error or modification
+     * to the underlying map.
+     *
+     * @param key
+     *        the key to be removed from the map if present.
+     *
+     * @returns the object previously stored in the Map or null if none present.
+     */
+    Object remove(String key);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMessageFacade.java
new file mode 100644
index 0000000..c8ab9ce
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsMessageFacade.java
@@ -0,0 +1,357 @@
+/**
+ * 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.jms.message.facade;
+
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.meta.JmsMessageId;
+
+/**
+ * The Message Facade interface defines the required mapping between a Provider's
+ * own Message type and the JMS Message types.  A Provider can implement the Facade
+ * interface and offer direct access to its message types without the need to
+ * copy to / from a more generic JMS message instance.
+ *
+ * TODO - What exceptions if any do we really need to be throwing here.  For get methods
+ *        we should synthesize an answer regardless and for set most of the checking for
+ *        JMS compliance happens in the JMS message level.  Methods like setMessageId and
+ *        setCorrelationId might need to although we should try and validate some at the
+ *        upper level.
+ */
+public interface JmsMessageFacade {
+
+    /**
+     * Returns the Message properties contained within this Message instance in
+     * a new Unmodifiable Map instance.
+     *
+     * @return a Map containing the properties of this Message that cannot be modified.
+     *
+     * @throws JMSException if an error occurs while accessing the Message properties.
+     */
+    public Map<String, Object> getProperties() throws JMSException;
+
+    /**
+     * @returns true if the given property exists within the message.
+     *
+     * @throws JMSException if an error occurs while accessing the Message properties.
+     */
+    boolean propertyExists(String key) throws JMSException;
+
+    /**
+     * Returns the property stored in the message accessed via the given key/
+     *
+     * @param key
+     *        the key used to access the given property.
+     *
+     * @throws JMSException if an error occurs while accessing the Message properties.
+     */
+    Object getProperty(String key) throws JMSException;
+
+    /**
+     * Sets the message property value using the supplied key to identify the value
+     * that should be set or updated.
+     *
+     * @param key
+     *        the key that identifies the message property.
+     * @param value
+     *        the value that is to be stored in the message.
+     *
+     * @throws JMSException if an error occurs while accessing the Message properties.
+     */
+    void setProperty(String key, Object value) throws JMSException;
+
+    /**
+     * Called when a message is sent to allow a Message instance to move the
+     * contents from a logical data structure to a binary form for transmission.
+     *
+     * @throws JMSException if an error occurs while preparing the message for send.
+     */
+    void onSend() throws JMSException;
+
+    /**
+     * This method should provide a quick check on the message to determine if
+     * there is any content actually contained within.
+     *
+     * @return true if the message content is non-empty.
+     */
+    boolean isEmpty();
+
+    /**
+     * Clears the contents of this Message.
+     */
+    void clearBody();
+
+    /**
+     * Clears any Message properties that exist for this Message instance.
+     *
+     * @throws JMSException if an error occurs while accessing the message properties.
+     */
+    void clearProperties();
+
+    /**
+     * Create a new instance and perform a deep copy of this object's
+     * contents.
+     *
+     * @throws JMSException if an error occurs while copying the message.
+     */
+    JmsMessageFacade copy() throws JMSException;
+
+    /**
+     * Return the internal message Id as a JmsMessageId wrapped value.
+     *
+     * @return a JmsMessageId that wraps the internal message Id.
+     */
+    JmsMessageId getMessageId();
+
+    /**
+     * Updates the message Id using the value of the given JmsMessageId.
+     *
+     * @param messageId
+     *        the new JmsMessageId value to assign as the message Id.
+     */
+    void setMessageId(JmsMessageId messageId);
+
+    /**
+     * Gets the timestamp assigned to the message when it was sent.
+     *
+     * @return the message timestamp value.
+     */
+    long getTimestamp();
+
+    /**
+     * Sets the timestamp value of this message.
+     *
+     * @param timestamp
+     *        the time that the message was sent by the provider.
+     */
+    void setTimestamp(long timestamp);
+
+    /**
+     * Returns the correlation ID set on this message if one exists, null otherwise.
+     *
+     * @return the set correlation ID or null if not set.
+     */
+    String getCorrelationId();
+
+    /**
+     * Sets the correlation ID for this message.
+     *
+     * @param correlationId
+     *        The correlation ID to set on this message, or null to clear.
+     */
+    void setCorrelationId(String correlationId);
+
+    /**
+     * Gets the set correlation ID of the message in raw bytes form.  If no ID was
+     * set then this method may return null or an empty byte array.
+     *
+     * @return a byte array containing the correlation ID value in raw form.
+     *
+     * @throws JMSException if an error occurs while accessing the property.
+     */
+    byte[] getCorrelationIdBytes() throws JMSException;
+
+    /**
+     * Sets the correlation ID of the message in raw byte form.  Setting the value
+     * as null or an empty byte array will clear any previously set value.  If the
+     * underlying protocol cannot convert or map the given byte value to it's own
+     * internal representation it should throw a JMSException indicating the error.
+     *
+     * @param correlationId
+     *        the byte array to use to set the message correlation ID.
+     */
+    void setCorrelationIdBytes(byte[] correlationId);
+
+    /**
+     * @return true if this message is tagged as being persistent.
+     */
+    boolean isPersistent();
+
+    /**
+     * Sets the persistent flag on this message.
+     *
+     * @param value
+     *        true if the message is to be marked as persistent.
+     */
+    void setPersistent(boolean value);
+
+    /**
+     * Returns the current redelivery count of the Message as set in the underlying
+     * message instance.
+     *
+     * @return the current redelivery count.
+     */
+    int getRedeliveryCounter();
+
+    /**
+     * Used to update the message redelivery after a local redelivery of the Message
+     * has been performed.
+     *
+     * @param redeliveryCount
+     *        the new redelivery count to assign the Message.
+     */
+    void setRedeliveryCounter(int redeliveryCount);
+
+    /**
+     * Used to quickly check if a message has been redelivered.
+     *
+     * @returns true if the message was redelivered, false otherwise.
+     */
+    boolean isRedelivered();
+
+    /**
+     * Used to set the redelivered state of a message.  This can serve to clear
+     * the redelivery counter or set its initial value to one.
+     *
+     * @param redelivered
+     *        true if the message is to be marked as redelivered, false otherwise.
+     */
+    void setRedelivered(boolean redelivered);
+
+    /**
+     * Returns the Type values as defined by the provider or set by the sending client.
+     *
+     * @return a String value that defines the message type.
+     */
+    String getType();
+
+    /**
+     * Sets the String value used to define the Message type by the client.
+     *
+     * @param type
+     *        the type value the client assigns to this message.
+     */
+    void setType(String type);
+
+    /**
+     * Returns the assigned priority value of this message in JMS ranged scoping.
+     *
+     * If the provider does not define a message priority value in its message objects
+     * or the value is not set in the message this method should return the JMS default
+     * value of 4.
+     *
+     * @return the priority value assigned to this message.
+     */
+    byte getPriority();
+
+    /**
+     * Sets the message priority for this message using a JMS priority scoped value.
+     *
+     * @param priority
+     *        the new priority value to set on this message.
+     */
+    void setPriority(byte priority);
+
+    /**
+     * Returns the set expiration time for this message.
+     *
+     * The value should be returned as an absolute time given in GMT time.
+     *
+     * @return the time that this message expires or zero if it never expires.
+     */
+    long getExpiration();
+
+    /**
+     * Sets an expiration time on this message.
+     *
+     * The expiration time will be given as an absolute time in GMT time.
+     *
+     * @param expiration
+     *        the time that this message should be considered as expired.
+     */
+    void setExpiration(long expiration);
+
+    /**
+     * Gets the Destination value that was assigned to this message at the time it was
+     * sent.
+     *
+     * @return the destination to which this message was originally sent.
+     */
+    JmsDestination getDestination();
+
+    /**
+     * Sets the Destination that this message is being sent to.
+     *
+     * @param destination
+     *        the destination that this message is being sent to.
+     */
+    void setDestination(JmsDestination destination);
+
+    /**
+     * Gets the Destination where replies for this Message are to be sent to.
+     *
+     * @return the reply to destination for this message or null if none set.
+     */
+    JmsDestination getReplyTo();
+
+    /**
+     * Sets the Destination where replies to this Message are to be sent.
+     *
+     * @param replyTo
+     *        the Destination where replies should be sent, or null to clear.
+     */
+    void setReplyTo(JmsDestination replyTo);
+
+    /**
+     * Returns the ID of the user that sent this message if available.
+     *
+     * @return the user ID that was in use when this message was sent or null if not set.
+     */
+    String getUserId();
+
+    /**
+     * Sets the User ID for the connection that is being used to send this message.
+     *
+     * @param userId
+     *        the user ID that sent this message or null to clear.
+     */
+    void setUserId(String userId);
+
+    /**
+     * Gets the Group ID that this message is assigned to.
+     *
+     * @return the Group ID this message was sent in.
+     */
+    String getGroupId();
+
+    /**
+     * Sets the Group ID to use for this message.
+     *
+     * @param groupId
+     *        the Group ID that this message is assigned to.
+     */
+    void setGroupId(String groupId);
+
+    /**
+     * Gets the assigned group sequence of this message.
+     *
+     * @return the assigned group sequence of this message.
+     */
+    int getGroupSequence();
+
+    /**
+     * Sets the group sequence value for this message.
+     *
+     * @param groupSequence
+     *        the group sequence value to assign this message.
+     */
+    void setGroupSequence(int groupSequence);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsObjectMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsObjectMessageFacade.java
new file mode 100644
index 0000000..337c427
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsObjectMessageFacade.java
@@ -0,0 +1,67 @@
+/**
+ * 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.jms.message.facade;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
+/**
+ * Interface for a message Facade that wraps an ObjectMessage based
+ * provider message.
+ */
+public interface JmsObjectMessageFacade extends JmsMessageFacade {
+
+    /**
+     * @returns a deep copy of this Message Facade including a complete copy
+     * of the byte contents of the wrapped message.
+     *
+     * @throws JMSException if an error occurs while copying this message.
+     */
+    @Override
+    JmsObjectMessageFacade copy() throws JMSException;
+
+    /**
+     * Gets the Object value that is contained in the provider message.
+     *
+     * If the Object is stored in some serialized form then the Provider must
+     * de-serialize the object prior to returning it.
+     *
+     * @return the de-serialized version of the contained object.
+     *
+     * @throws IOException if the provider fails to get the object due to some internal error.
+     * @throws ClassNotFoundException if object de-serialization fails because the ClassLoader
+     *                                cannot find the Class locally.
+     */
+    Serializable getObject() throws IOException, ClassNotFoundException;
+
+    /**
+     * Stores the given object into the provider Message.
+     *
+     * In order for the provider to be fully JMS compliant the set Object should be
+     * immediately serialized and stored so that future modifications to the object
+     * are not reflected in the stored version of the object.
+     *
+     * @param value
+     *        the new value to write to the provider message.
+     *
+     * @throws IOException if the provider fails to store the object due to some internal error.
+     */
+    void setObject(Serializable value) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsStreamMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsStreamMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsStreamMessageFacade.java
new file mode 100644
index 0000000..4e3468e
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsStreamMessageFacade.java
@@ -0,0 +1,76 @@
+/**
+ * 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.jms.message.facade;
+
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+
+/**
+ * Interface for a Message Facade that wraps a stream or list based provider
+ * message instance.  The interface provides the basic entry points into a
+ * stream style message where primitive values are read and written as opaque
+ * objects.
+ */
+public interface JmsStreamMessageFacade extends JmsMessageFacade {
+
+    /**
+     * @returns a deep copy of this Message Facade including a complete copy
+     * of the byte contents of the wrapped message.
+     */
+    @Override
+    JmsStreamMessageFacade copy() throws JMSException;
+
+    /**
+     * @returns true if the stream contains another element beyond the current.
+     */
+    boolean hasNext();
+
+    /**
+     * Peek and return the next element in the stream.  If the stream has been fully read
+     * then this method should throw a MessageEOFException.  Multiple calls to peek should
+     * return the same element.
+     *
+     * @returns the next value in the stream without removing it.
+     *
+     * @throws MessageEOFException if end of message stream has been reached.
+     */
+    Object peek() throws MessageEOFException;
+
+    /**
+     * Pops the next element in the stream.
+     *
+     * @throws MessageEOFException if end of message stream has been reached.
+     */
+    void pop() throws MessageEOFException;
+
+    /**
+     * Writes a new object value to the stream.
+     *
+     * If the value provided is a byte[] its entry then it is assumed that it was
+     * copied by the caller and its value will not be altered by the provider.
+     *
+     * @param value
+     *        The object value to be written to the stream.
+     */
+    void put(Object value);
+
+    /**
+     * Reset the position of the stream to the beginning.
+     */
+    void reset();
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsTextMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsTextMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsTextMessageFacade.java
new file mode 100644
index 0000000..5fc320b
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/JmsTextMessageFacade.java
@@ -0,0 +1,53 @@
+/**
+ * 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.jms.message.facade;
+
+import javax.jms.JMSException;
+
+/**
+ * A Facade around a provider message that behaves like a TextMessage instance.
+ */
+public interface JmsTextMessageFacade extends JmsMessageFacade {
+
+    /**
+     * Creates a copy of this JmsTextMessageFacade and its underlying
+     * provider message instance.
+     *
+     * @returns a new JmsTextMessageFacade that wraps a duplicate message.
+     */
+    @Override
+    JmsTextMessageFacade copy() throws JMSException;
+
+    /**
+     * Returns the String payload of the Message or null if none set.
+     *
+     * @return the String value contained in the message.
+     *
+     * @throws JMSException if an error occurs while decoding text payload.
+     */
+    String getText() throws JMSException;
+
+    /**
+     * Sets the new String payload of the wrapped message, or clears the old value
+     * if the given value is null.
+     *
+     * @param value
+     *        the new String payload, or null to clear the contents.
+     */
+    void setText(String value);
+
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultBytesMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultBytesMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultBytesMessageFacade.java
new file mode 100644
index 0000000..6870eb6
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultBytesMessageFacade.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.jms.message.facade.defaults;
+
+import org.apache.qpid.jms.message.facade.JmsBytesMessageFacade;
+import org.fusesource.hawtbuf.Buffer;
+
+/**
+ * A default implementation of the JmsBytesMessageFacade that simply holds a raw Buffer
+ */
+public final class JmsDefaultBytesMessageFacade extends JmsDefaultMessageFacade implements JmsBytesMessageFacade {
+
+    private Buffer content;
+
+    @Override
+    public JmsMsgType getMsgType() {
+        return JmsMsgType.BYTES;
+    }
+
+    @Override
+    public JmsDefaultBytesMessageFacade copy() {
+        JmsDefaultBytesMessageFacade copy = new JmsDefaultBytesMessageFacade();
+        copyInto(copy);
+        if (this.content != null) {
+            copy.setContent(this.content.deepCopy());
+        }
+
+        return copy;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        if (content == null || content.length() == 0) {
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void clearBody() {
+        this.content = null;
+    }
+
+    @Override
+    public Buffer getContent() {
+        return content;
+    }
+
+    @Override
+    public void setContent(Buffer content) {
+        this.content = content;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMapMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMapMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMapMessageFacade.java
new file mode 100644
index 0000000..33da603
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMapMessageFacade.java
@@ -0,0 +1,75 @@
+/**
+ * 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.jms.message.facade.defaults;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.jms.message.facade.JmsMapMessageFacade;
+
+/**
+ * Simple implementation of the JmsMapMessageFacade used for testing.
+ */
+public class JmsDefaultMapMessageFacade extends JmsDefaultMessageFacade implements JmsMapMessageFacade {
+
+    protected final Map<String, Object> map = new HashMap<String, Object>();
+
+    @Override
+    public JmsMsgType getMsgType() {
+        return JmsMsgType.MAP;
+    }
+
+    @Override
+    public JmsDefaultMapMessageFacade copy() {
+        JmsDefaultMapMessageFacade copy = new JmsDefaultMapMessageFacade();
+        copyInto(copy);
+        copy.map.putAll(map);
+        return copy;
+    }
+
+    @Override
+    public Enumeration<String> getMapNames() {
+        return Collections.enumeration(map.keySet());
+    }
+
+    @Override
+    public boolean itemExists(String key) {
+        return map.containsKey(key);
+    }
+
+    @Override
+    public Object get(String key) {
+        return map.get(key);
+    }
+
+    @Override
+    public void put(String key, Object value) {
+        map.put(key, value);
+    }
+
+    @Override
+    public Object remove(String key) {
+        return map.remove(key);
+    }
+
+    @Override
+    public void clearBody() {
+        map.clear();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMessageFacade.java
new file mode 100644
index 0000000..8a501cc
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultMessageFacade.java
@@ -0,0 +1,316 @@
+/**
+ * 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.jms.message.facade.defaults;
+
+import static org.fusesource.hawtbuf.Buffer.ascii;
+
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.message.facade.JmsMessageFacade;
+import org.apache.qpid.jms.meta.JmsMessageId;
+import org.fusesource.hawtbuf.AsciiBuffer;
+
+/**
+ * A default implementation of the JmsMessageFaceade that provides a generic
+ * message instance which can be used instead of implemented in Provider specific
+ * version that maps to a Provider message object.
+ */
+public class JmsDefaultMessageFacade implements JmsMessageFacade {
+
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+
+    public static enum JmsMsgType {
+        MESSAGE("jms/message"),
+        BYTES("jms/bytes-message"),
+        MAP("jms/map-message"),
+        OBJECT("jms/object-message"),
+        STREAM("jms/stream-message"),
+        TEXT("jms/text-message"),
+        TEXT_NULL("jms/text-message-null");
+
+        public final AsciiBuffer buffer = new AsciiBuffer(this.name());
+        public final AsciiBuffer mime;
+
+        JmsMsgType(String mime) {
+            this.mime = (ascii(mime));
+        }
+    }
+
+    protected Map<String, Object> properties = new HashMap<String, Object>();
+
+    protected byte priority = javax.jms.Message.DEFAULT_PRIORITY;
+    protected String groupId;
+    protected int groupSequence;
+    protected JmsMessageId messageId;
+    protected long expiration;
+    protected long timestamp;
+    protected String correlationId;
+    protected boolean persistent;
+    protected int redeliveryCount;
+    protected String type;
+    protected JmsDestination destination;
+    protected JmsDestination replyTo;
+    protected String userId;
+
+    public JmsMsgType getMsgType() {
+        return JmsMsgType.MESSAGE;
+    }
+
+    @Override
+    public JmsDefaultMessageFacade copy() {
+        JmsDefaultMessageFacade copy = new JmsDefaultMessageFacade();
+        copyInto(copy);
+        return copy;
+    }
+
+    protected void copyInto(JmsDefaultMessageFacade target) {
+        target.priority = this.priority;
+        target.groupSequence = this.groupSequence;
+        target.groupId = this.groupId;
+        target.expiration = this.expiration;
+        target.timestamp = this.timestamp;
+        target.correlationId = this.correlationId;
+        target.persistent = this.persistent;
+        target.redeliveryCount = this.redeliveryCount;
+        target.type = this.type;
+        target.destination = this.destination;
+        target.replyTo = this.replyTo;
+        target.userId = this.userId;
+
+        if (this.messageId != null) {
+            target.messageId = this.messageId.copy();
+        }
+
+        if (this.properties != null) {
+            target.properties = new HashMap<String, Object>(this.properties);
+        } else {
+            target.properties = null;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getProperties() throws JMSException {
+        lazyCreateProperties();
+        return properties;
+    }
+
+    @Override
+    public boolean propertyExists(String key) throws JMSException {
+        return this.properties.containsKey(key);
+    }
+
+    @Override
+    public Object getProperty(String key) throws JMSException {
+        return this.properties.get(key);
+    }
+
+    @Override
+    public void setProperty(String key, Object value) throws JMSException {
+        this.properties.put(key, value);
+    }
+
+    @Override
+    public void onSend() throws JMSException {
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return true;
+    }
+
+    @Override
+    public void clearBody() {
+    }
+
+    @Override
+    public void clearProperties() {
+        properties.clear();
+    }
+
+    @Override
+    public JmsMessageId getMessageId() {
+        return this.messageId;
+    }
+
+    @Override
+    public void setMessageId(JmsMessageId messageId) {
+        this.messageId = messageId;
+    }
+
+    @Override
+    public long getTimestamp() {
+        return this.timestamp;
+    }
+
+    @Override
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    @Override
+    public String getCorrelationId() {
+        return correlationId;
+    }
+
+    @Override
+    public void setCorrelationId(String correlationId) {
+        this.correlationId = correlationId;
+    }
+
+    @Override
+    public byte[] getCorrelationIdBytes() {
+        return correlationId.getBytes(UTF8);
+    }
+
+    @Override
+    public void setCorrelationIdBytes(byte[] correlationId) {
+        if (correlationId != null && correlationId.length > 0) {
+            this.correlationId = new String(correlationId, UTF8);
+        } else {
+            this.correlationId = null;
+        }
+    }
+
+    @Override
+    public boolean isPersistent() {
+        return this.persistent;
+    }
+
+    @Override
+    public void setPersistent(boolean value) {
+        this.persistent = value;
+    }
+
+    @Override
+    public int getRedeliveryCounter() {
+        return this.redeliveryCount;
+    }
+
+    @Override
+    public void setRedeliveryCounter(int redeliveryCount) {
+        this.redeliveryCount = redeliveryCount;
+    }
+
+    @Override
+    public boolean isRedelivered() {
+        return redeliveryCount > 0;
+    }
+
+    @Override
+    public void setRedelivered(boolean redelivered) {
+        if (redelivered) {
+            if (!isRedelivered()) {
+                setRedeliveryCounter(1);
+            }
+        } else {
+            if (isRedelivered()) {
+                setRedeliveryCounter(0);
+            }
+        }
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @Override
+    public byte getPriority() {
+        return priority;
+    }
+
+    @Override
+    public void setPriority(byte priority) {
+        this.priority = priority;
+    }
+
+    @Override
+    public long getExpiration() {
+        return expiration;
+    }
+
+    @Override
+    public void setExpiration(long expiration) {
+        this.expiration = expiration;
+    }
+
+    @Override
+    public JmsDestination getDestination() {
+        return this.destination;
+    }
+
+    @Override
+    public void setDestination(JmsDestination destination) {
+        this.destination = destination;
+    }
+
+    @Override
+    public JmsDestination getReplyTo() {
+        return this.replyTo;
+    }
+
+    @Override
+    public void setReplyTo(JmsDestination replyTo) {
+        this.replyTo = replyTo;
+    }
+
+    @Override
+    public String getUserId() {
+        return this.userId;
+    }
+
+    @Override
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    @Override
+    public String getGroupId() {
+        return this.groupId;
+    }
+
+    @Override
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    @Override
+    public int getGroupSequence() {
+        return this.groupSequence;
+    }
+
+    @Override
+    public void setGroupSequence(int groupSequence) {
+        this.groupSequence = groupSequence;
+    }
+
+    private void lazyCreateProperties() {
+        if (properties == null) {
+            properties = new HashMap<String, Object>();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultObjectMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultObjectMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultObjectMessageFacade.java
new file mode 100644
index 0000000..89442b9
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultObjectMessageFacade.java
@@ -0,0 +1,105 @@
+/**
+ * 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.jms.message.facade.defaults;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import org.apache.qpid.jms.message.facade.JmsObjectMessageFacade;
+import org.apache.qpid.jms.util.ClassLoadingAwareObjectInputStream;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtbuf.DataByteArrayInputStream;
+import org.fusesource.hawtbuf.DataByteArrayOutputStream;
+
+/**
+ * Default implementation for a JMS Object Message Facade.
+ */
+public class JmsDefaultObjectMessageFacade extends JmsDefaultMessageFacade implements JmsObjectMessageFacade {
+
+    private Buffer object;
+
+    public Buffer getSerializedObject() {
+        return object;
+    }
+
+    public void setSerializedObject(Buffer object) {
+        this.object = object;
+    }
+
+    @Override
+    public JmsMsgType getMsgType() {
+        return JmsMsgType.OBJECT;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return object == null || object.isEmpty();
+    }
+
+    @Override
+    public JmsDefaultObjectMessageFacade copy() {
+        JmsDefaultObjectMessageFacade copy = new JmsDefaultObjectMessageFacade();
+        copyInto(copy);
+        if (!isEmpty()) {
+            copy.object = object.deepCopy();
+        }
+
+        return copy;
+    }
+
+    @Override
+    public void clearBody() {
+        this.object = null;
+    }
+
+    @Override
+    public Serializable getObject() throws IOException, ClassNotFoundException {
+
+        if (isEmpty()) {
+            return null;
+        }
+
+        Serializable serialized = null;
+
+        try (DataByteArrayInputStream dataIn = new DataByteArrayInputStream(object);
+             ClassLoadingAwareObjectInputStream objIn = new ClassLoadingAwareObjectInputStream(dataIn)) {
+
+            serialized = (Serializable) objIn.readObject();
+        }
+
+        return serialized;
+    }
+
+    @Override
+    public void setObject(Serializable value) throws IOException {
+        Buffer serialized = null;
+        if (value != null) {
+            try (DataByteArrayOutputStream baos = new DataByteArrayOutputStream();
+                 ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+
+                oos.writeObject(value);
+                oos.flush();
+                oos.close();
+
+                serialized = baos.toBuffer();
+            }
+        }
+
+        this.object = serialized;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultStreamMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultStreamMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultStreamMessageFacade.java
new file mode 100644
index 0000000..1a0a17a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultStreamMessageFacade.java
@@ -0,0 +1,85 @@
+/**
+ * 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.jms.message.facade.defaults;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jms.MessageEOFException;
+
+import org.apache.qpid.jms.message.facade.JmsStreamMessageFacade;
+
+/**
+ * Default implementation of the JmsStreamMessageFacade
+ */
+public class JmsDefaultStreamMessageFacade extends JmsDefaultMessageFacade implements JmsStreamMessageFacade {
+
+    private final List<Object> stream = new ArrayList<Object>();
+    private int index = -1;
+
+    @Override
+    public JmsMsgType getMsgType() {
+        return JmsMsgType.STREAM;
+    }
+
+    @Override
+    public JmsDefaultStreamMessageFacade copy() {
+        JmsDefaultStreamMessageFacade copy = new JmsDefaultStreamMessageFacade();
+        copyInto(copy);
+        copy.stream.addAll(stream);
+        return copy;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return !stream.isEmpty() && index < stream.size();
+    }
+
+    @Override
+    public Object peek() throws MessageEOFException {
+        if (stream.isEmpty() || index + 1 >= stream.size()) {
+            throw new MessageEOFException("Attempted to read past the end of the stream");
+        }
+
+        return stream.get(index + 1);
+    }
+
+    @Override
+    public void pop() throws MessageEOFException {
+        if (stream.isEmpty() || index + 1 >= stream.size()) {
+            throw new MessageEOFException("Attempted to read past the end of the stream");
+        }
+
+        index++;
+    }
+
+    @Override
+    public void put(Object value) {
+        stream.add(value);
+    }
+
+    @Override
+    public void clearBody() {
+        stream.clear();
+        index = -1;
+    }
+
+    @Override
+    public void reset() {
+        index = -1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultTextMessageFacade.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultTextMessageFacade.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultTextMessageFacade.java
new file mode 100644
index 0000000..c21d5c1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/facade/defaults/JmsDefaultTextMessageFacade.java
@@ -0,0 +1,62 @@
+/**
+ * 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.jms.message.facade.defaults;
+
+import org.apache.qpid.jms.message.facade.JmsTextMessageFacade;
+
+/**
+ * Default implementation of the JmsTextMessageFacade.
+ */
+public final class JmsDefaultTextMessageFacade extends JmsDefaultMessageFacade implements JmsTextMessageFacade {
+
+    private String text;
+
+    @Override
+    public JmsMsgType getMsgType() {
+        return JmsMsgType.TEXT;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return text != null && !text.isEmpty();
+    }
+
+    @Override
+    public JmsDefaultTextMessageFacade copy() {
+        JmsDefaultTextMessageFacade copy = new JmsDefaultTextMessageFacade();
+        copyInto(copy);
+        if (text != null) {
+            copy.setText(text);
+        }
+        return copy;
+    }
+
+    @Override
+    public void clearBody() {
+        this.text = null;
+    }
+
+    @Override
+    public String getText() {
+        return text;
+    }
+
+    @Override
+    public void setText(String text) {
+        this.text = text;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsAbstractResourceId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsAbstractResourceId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsAbstractResourceId.java
new file mode 100644
index 0000000..93248dd
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsAbstractResourceId.java
@@ -0,0 +1,47 @@
+/**
+ * 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.jms.meta;
+
+/**
+ * Base class for all JmsResourceId instances.
+ */
+public abstract class JmsAbstractResourceId implements JmsResourceId {
+
+    protected transient Object providerHint;
+    protected transient Object providerId;
+    protected transient int hashCode;
+
+    @Override
+    public void setProviderHint(Object hint) {
+        this.providerHint = hint;
+    }
+
+    @Override
+    public Object getProviderHint() {
+        return providerHint;
+    }
+
+    @Override
+    public void setProviderId(Object id) {
+        this.providerId = id;
+    }
+
+    @Override
+    public Object getProviderId() {
+        return providerId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionId.java
new file mode 100644
index 0000000..05cda08
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionId.java
@@ -0,0 +1,76 @@
+/**
+ * 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.jms.meta;
+
+public class JmsConnectionId extends JmsAbstractResourceId implements Comparable<JmsConnectionId> {
+
+    private final String value;
+
+    public JmsConnectionId(String connectionId) {
+        this.value = connectionId;
+    }
+
+    public JmsConnectionId(JmsConnectionId id) {
+        this.value = id.getValue();
+    }
+
+    public JmsConnectionId(JmsSessionId id) {
+        this.value = id.getConnectionId();
+    }
+
+    public JmsConnectionId(JmsProducerId id) {
+        this.value = id.getConnectionId();
+    }
+
+    public JmsConnectionId(JmsConsumerId id) {
+        this.value = id.getConnectionId();
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) {
+            hashCode = value.hashCode();
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || o.getClass() != JmsConnectionId.class) {
+            return false;
+        }
+        JmsConnectionId id = (JmsConnectionId) o;
+        return value.equals(id.value);
+    }
+
+    @Override
+    public String toString() {
+        return value;
+    }
+
+    @Override
+    public int compareTo(JmsConnectionId o) {
+        return value.compareTo(o.value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
new file mode 100644
index 0000000..efdc6eb
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConnectionInfo.java
@@ -0,0 +1,251 @@
+/**
+ * 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.jms.meta;
+
+import org.apache.qpid.jms.util.ToStringSupport;
+
+/**
+ * Meta object that contains the JmsConnection identification and configuration
+ * options.  Providers can extend this to add Provider specific data as needed.
+ */
+public final class JmsConnectionInfo implements JmsResource, Comparable<JmsConnectionInfo> {
+
+    public static final long INFINITE = -1;
+    public static final long DEFAULT_CONNECT_TIMEOUT = 15000;
+    public static final long DEFAULT_CLOSE_TIMEOUT = 15000;
+    public static final long DEFAULT_SEND_TIMEOUT = INFINITE;
+    public static final long DEFAULT_REQUEST_TIMEOUT = INFINITE;
+
+    private final JmsConnectionId connectionId;
+    private String clientId;
+    private String clientIp;
+    private String username;
+    private String password;
+    private boolean forceAsyncSend;
+    private boolean alwaysSyncSend;
+    private boolean omitHost;
+    private boolean watchRemoteDestinations;
+    public long sendTimeout = DEFAULT_SEND_TIMEOUT;
+    public long requestTimeout = DEFAULT_REQUEST_TIMEOUT;
+    public long connectTimeout = DEFAULT_CONNECT_TIMEOUT;
+    public long closeTimeout = DEFAULT_CLOSE_TIMEOUT;
+    private String queuePrefix = "/queue/";
+    private String topicPrefix = "/topic/";
+    private String tempQueuePrefix = "/temp-queue/";
+    private String tempTopicPrefix = "/temp-topic/";
+
+    public JmsConnectionInfo(JmsConnectionId connectionId) {
+        this.connectionId = connectionId;
+    }
+
+    public JmsConnectionInfo copy() {
+        JmsConnectionInfo copy = new JmsConnectionInfo(connectionId);
+        copy(copy);
+        return copy;
+    }
+
+    private void copy(JmsConnectionInfo copy) {
+        copy.clientId = clientId;
+        copy.username = username;
+        copy.password = password;
+        copy.clientIp = clientIp;
+        copy.forceAsyncSend = forceAsyncSend;
+        copy.alwaysSyncSend = alwaysSyncSend;
+        copy.omitHost = omitHost;
+        copy.sendTimeout = sendTimeout;
+        copy.requestTimeout = requestTimeout;
+        copy.closeTimeout = closeTimeout;
+        copy.queuePrefix = queuePrefix;
+        copy.topicPrefix = topicPrefix;
+        copy.tempQueuePrefix = tempQueuePrefix;
+        copy.tempTopicPrefix = tempTopicPrefix;
+    }
+
+    public boolean isForceAsyncSend() {
+        return forceAsyncSend;
+    }
+
+    public void setForceAsyncSends(boolean forceAsyncSend) {
+        this.forceAsyncSend = forceAsyncSend;
+    }
+
+    public boolean isAlwaysSyncSend() {
+        return alwaysSyncSend;
+    }
+
+    public void setAlwaysSyncSend(boolean alwaysSyncSend) {
+        this.alwaysSyncSend = alwaysSyncSend;
+    }
+
+    public JmsConnectionId getConnectionId() {
+        return connectionId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientIp() {
+        return clientIp;
+    }
+
+    public void setClientIp(String clientIp) {
+        this.clientIp = clientIp;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public boolean isOmitHost() {
+        return omitHost;
+    }
+
+    public void setOmitHost(boolean omitHost) {
+        this.omitHost = omitHost;
+    }
+
+    public String getQueuePrefix() {
+        return queuePrefix;
+    }
+
+    public void setQueuePrefix(String queuePrefix) {
+        this.queuePrefix = queuePrefix;
+    }
+
+    public String getTopicPrefix() {
+        return topicPrefix;
+    }
+
+    public void setTopicPrefix(String topicPrefix) {
+        this.topicPrefix = topicPrefix;
+    }
+
+    public String getTempQueuePrefix() {
+        return tempQueuePrefix;
+    }
+
+    public void setTempQueuePrefix(String tempQueuePrefix) {
+        this.tempQueuePrefix = tempQueuePrefix;
+    }
+
+    public String getTempTopicPrefix() {
+        return tempTopicPrefix;
+    }
+
+    public void setTempTopicPrefix(String tempTopicPrefix) {
+        this.tempTopicPrefix = tempTopicPrefix;
+    }
+
+    public long getCloseTimeout() {
+        return closeTimeout;
+    }
+
+    public void setCloseTimeout(long closeTimeout) {
+        this.closeTimeout = closeTimeout;
+    }
+
+    public long getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    public void setConnectTimeout(long connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    public long getSendTimeout() {
+        return sendTimeout;
+    }
+
+    public void setSendTimeout(long sendTimeout) {
+        this.sendTimeout = sendTimeout;
+    }
+
+    public long getRequestTimeout() {
+        return requestTimeout;
+    }
+
+    public void setRequestTimeout(long requestTimeout) {
+        this.requestTimeout = requestTimeout;
+    }
+
+    public boolean isWatchRemoteDestinations() {
+        return watchRemoteDestinations;
+    }
+
+    public void setWatchRemoteDestinations(boolean watchRemoteDestinations) {
+        this.watchRemoteDestinations = watchRemoteDestinations;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringSupport.toString(this);
+    }
+
+    @Override
+    public int hashCode() {
+        return this.connectionId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        JmsConnectionInfo other = (JmsConnectionInfo) obj;
+
+        if (connectionId == null && other.connectionId != null) {
+            return false;
+        } else if (!connectionId.equals(other.connectionId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int compareTo(JmsConnectionInfo other) {
+        return this.connectionId.compareTo(other.connectionId);
+    }
+
+    @Override
+    public void visit(JmsResourceVistor vistor) throws Exception {
+        vistor.processConnectionInfo(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerId.java
new file mode 100644
index 0000000..2ea3d44
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerId.java
@@ -0,0 +1,121 @@
+/**
+ * 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.jms.meta;
+
+public final class JmsConsumerId extends JmsAbstractResourceId implements Comparable<JmsConsumerId> {
+
+    private String connectionId;
+    private long sessionId;
+    private long value;
+
+    private transient String key;
+    private transient JmsSessionId parentId;
+
+    public JmsConsumerId(String connectionId, long sessionId, long consumerId) {
+        this.connectionId = connectionId;
+        this.sessionId = sessionId;
+        this.value = consumerId;
+    }
+
+    public JmsConsumerId(JmsSessionId sessionId, long consumerId) {
+        this.connectionId = sessionId.getConnectionId();
+        this.sessionId = sessionId.getValue();
+        this.value = consumerId;
+        this.parentId = sessionId;
+    }
+
+    public JmsConsumerId(JmsConsumerId id) {
+        this.connectionId = id.getConnectionId();
+        this.sessionId = id.getSessionId();
+        this.value = id.getValue();
+        this.parentId = id.getParentId();
+    }
+
+    public JmsConsumerId(String consumerKey) throws IllegalArgumentException {
+        // Parse off the consumer Id value
+        int p = consumerKey.lastIndexOf(":");
+        if (p >= 0) {
+            value = Long.parseLong(consumerKey.substring(p + 1));
+            consumerKey = consumerKey.substring(0, p);
+        }
+        setConsumerSessionKey(consumerKey);
+    }
+
+    public JmsSessionId getParentId() {
+        if (parentId == null) {
+            parentId = new JmsSessionId(this);
+        }
+        return parentId;
+    }
+
+    public String getConnectionId() {
+        return connectionId;
+    }
+
+    public long getSessionId() {
+        return sessionId;
+    }
+
+    public long getValue() {
+        return value;
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) {
+            hashCode = connectionId.hashCode() ^ (int) sessionId ^ (int) value;
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || o.getClass() != JmsConsumerId.class) {
+            return false;
+        }
+        JmsConsumerId id = (JmsConsumerId) o;
+        return sessionId == id.sessionId && value == id.value && connectionId.equals(id.connectionId);
+    }
+
+    @Override
+    public String toString() {
+        if (key == null) {
+            key = connectionId + ":" + sessionId + ":" + value;
+        }
+        return key;
+    }
+
+    @Override
+    public int compareTo(JmsConsumerId other) {
+        return toString().compareTo(other.toString());
+    }
+
+    private void setConsumerSessionKey(String sessionKey) {
+        // Parse off the value of the session Id
+        int p = sessionKey.lastIndexOf(":");
+        if (p >= 0) {
+            sessionId = Long.parseLong(sessionKey.substring(p + 1));
+            sessionKey = sessionKey.substring(0, p);
+        }
+
+        // The rest is the value of the connection Id.
+        connectionId = sessionKey;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
new file mode 100644
index 0000000..2747453
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsConsumerInfo.java
@@ -0,0 +1,187 @@
+/**
+ * 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.jms.meta;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.util.ToStringSupport;
+
+public final class JmsConsumerInfo implements JmsResource, Comparable<JmsConsumerInfo> {
+
+    protected final JmsConsumerId consumerId;
+    protected JmsDestination destination;
+    protected int prefetchSize;
+    protected boolean browser;
+    protected String selector;
+    protected String clientId;
+    protected String subscriptionName;
+    protected boolean noLocal;
+    protected int acknowledgementMode;
+
+    // Can be used to track the last consumed message.
+    private transient long lastDeliveredSequenceId;
+
+    public JmsConsumerInfo(JmsConsumerId consumerId) {
+        this.consumerId = consumerId;
+    }
+
+    public JmsConsumerInfo(JmsSessionInfo sessionInfo, long consumerId) {
+        this.consumerId = new JmsConsumerId(sessionInfo.getSessionId(), consumerId);
+    }
+
+    public JmsConsumerInfo copy() {
+        JmsConsumerInfo info = new JmsConsumerInfo(consumerId);
+        copy(info);
+        return info;
+    }
+
+    private void copy(JmsConsumerInfo info) {
+        info.destination = destination;
+        info.prefetchSize = prefetchSize;
+        info.browser = browser;
+        info.selector = selector;
+        info.clientId = clientId;
+        info.subscriptionName = subscriptionName;
+        info.noLocal = noLocal;
+        info.acknowledgementMode = acknowledgementMode;
+    }
+
+    public boolean isDurable() {
+        return subscriptionName != null;
+    }
+
+    public JmsConsumerId getConsumerId() {
+        return consumerId;
+    }
+
+    public boolean isBrowser() {
+        return browser;
+    }
+
+    public void setBrowser(boolean browser) {
+        this.browser = browser;
+    }
+
+    public JmsDestination getDestination() {
+        return destination;
+    }
+
+    public void setDestination(JmsDestination destination) {
+        this.destination = destination;
+    }
+
+    public int getPrefetchSize() {
+        return prefetchSize;
+    }
+
+    public void setPrefetchSize(int prefetchSize) {
+        this.prefetchSize = prefetchSize;
+    }
+
+    public String getSelector() {
+        return selector;
+    }
+
+    public void setSelector(String selector) {
+        this.selector = selector;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getSubscriptionName() {
+        return subscriptionName;
+    }
+
+    public void setSubscriptionName(String durableSubscriptionId) {
+        this.subscriptionName = durableSubscriptionId;
+    }
+
+    public boolean isNoLocal() {
+        return noLocal;
+    }
+
+    public void setNoLocal(boolean noLocal) {
+        this.noLocal = noLocal;
+    }
+
+    public void setLastDeliveredSequenceId(long lastDeliveredSequenceId) {
+        this.lastDeliveredSequenceId  = lastDeliveredSequenceId;
+    }
+
+    public long getLastDeliveredSequenceId() {
+        return lastDeliveredSequenceId;
+    }
+
+    public JmsSessionId getParentId() {
+        return this.consumerId.getParentId();
+    }
+
+    public int getAcknowledgementMode() {
+        return acknowledgementMode;
+    }
+
+    public void setAcknowledgementMode(int acknowledgementMode) {
+        this.acknowledgementMode = acknowledgementMode;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringSupport.toString(this);
+    }
+
+    @Override
+    public int hashCode() {
+        return (consumerId == null) ? 0 : consumerId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        JmsConsumerInfo other = (JmsConsumerInfo) obj;
+
+        if (consumerId == null && other.consumerId != null) {
+            return false;
+        } else if (!consumerId.equals(other.consumerId)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int compareTo(JmsConsumerInfo other) {
+        return this.consumerId.compareTo(other.consumerId);
+    }
+
+    @Override
+    public void visit(JmsResourceVistor vistor) throws Exception {
+        vistor.processConsumerInfo(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsDefaultResourceVisitor.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsDefaultResourceVisitor.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsDefaultResourceVisitor.java
new file mode 100644
index 0000000..ba2d3dc
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsDefaultResourceVisitor.java
@@ -0,0 +1,51 @@
+/**
+ * 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.jms.meta;
+
+import org.apache.qpid.jms.JmsDestination;
+
+/**
+ * Default Visitor implementation that does nothing in each method to
+ * make custom implementations simpler by only needing to override the
+ * visitation cases they need to handle.
+ */
+public class JmsDefaultResourceVisitor implements JmsResourceVistor{
+
+    @Override
+    public void processConnectionInfo(JmsConnectionInfo connectionInfo) throws Exception {
+    }
+
+    @Override
+    public void processSessionInfo(JmsSessionInfo sessionInfo) throws Exception {
+    }
+
+    @Override
+    public void processConsumerInfo(JmsConsumerInfo consumerInfo) throws Exception {
+    }
+
+    @Override
+    public void processProducerInfo(JmsProducerInfo producerInfo) throws Exception {
+    }
+
+    @Override
+    public void processDestination(JmsDestination destination) throws Exception {
+    }
+
+    @Override
+    public void processTransactionInfo(JmsTransactionInfo transactionInfo) throws Exception {
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsMessageId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsMessageId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsMessageId.java
new file mode 100644
index 0000000..0b1136b
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsMessageId.java
@@ -0,0 +1,109 @@
+/**
+ * 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.jms.meta;
+
+
+/**
+ * JMS Message Id class used to uniquely identify messages for the JMS Framework.
+ */
+public class JmsMessageId extends JmsAbstractResourceId implements Comparable<JmsMessageId> {
+
+    protected Object messageId;
+
+    public JmsMessageId(JmsProducerInfo producerInfo, long producerSequenceId) {
+        this(producerInfo.getProducerId(), producerSequenceId);
+    }
+
+    public JmsMessageId(JmsProducerId producerId, long producerSequenceId) {
+        this(producerId.toString(), producerSequenceId);
+    }
+
+    public JmsMessageId(String producerId, long producerSequenceId) {
+        this(producerId + "-" + producerSequenceId);
+    }
+
+    public JmsMessageId(Object messageId) {
+        setValue(messageId);
+    }
+
+    public JmsMessageId copy() {
+        JmsMessageId copy = new JmsMessageId(messageId);
+        return copy;
+    }
+
+    /**
+     * Sets the value as a opaque object
+     *
+     * @param messageId
+     *        The new message Id value for this instance.
+     */
+    public void setValue(Object messageId) {
+        this.messageId = messageId;
+    }
+
+    /**
+     * @return the set message ID value.
+     */
+    public Object getValue() {
+        return messageId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        //TODO: handle messages with no messageId value
+        if (this == o) {
+            return true;
+        }
+        if (o == null || o.getClass() != getClass()) {
+            return false;
+        }
+
+        JmsMessageId id = (JmsMessageId) o;
+        return id.messageId.equals(this.messageId);
+    }
+
+    @Override
+    public int hashCode() {
+        //TODO: handle messages with no messageId value
+        if (hashCode == 0) {
+            hashCode = messageId.hashCode();
+        }
+        return hashCode;
+    }
+
+    @Override
+    public int compareTo(JmsMessageId other) {
+        //TODO: handle messages with no messageId value
+        int result = -1;
+        if (other != null) {
+            result = this.toString().compareTo(other.toString());
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        String result = messageId.toString();
+        if (result != null) {
+            if (!result.startsWith("ID:")) {
+                result = "ID:" + messageId;
+            }
+        }
+
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerId.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerId.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerId.java
new file mode 100644
index 0000000..501667a
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerId.java
@@ -0,0 +1,123 @@
+/**
+ * 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.jms.meta;
+
+public final class JmsProducerId extends JmsAbstractResourceId implements Comparable<JmsProducerId> {
+
+    private String connectionId;
+    private long sessionId;
+    private long value;
+
+    private transient String key;
+    private transient JmsSessionId parentId;
+
+    public JmsProducerId(JmsSessionId sessionId, long producerId) {
+        this.connectionId = sessionId.getConnectionId();
+        this.sessionId = sessionId.getValue();
+        this.value = producerId;
+        this.parentId = sessionId;
+    }
+
+    public JmsProducerId(JmsProducerId id) {
+        this.connectionId = id.getConnectionId();
+        this.sessionId = id.getSessionId();
+        this.value = id.getValue();
+        this.parentId = id.getParentId();
+    }
+
+    public JmsProducerId(String connectionId, long sessionId, long producerId) {
+        this.connectionId = connectionId;
+        this.sessionId = sessionId;
+        this.value = producerId;
+    }
+
+    public JmsProducerId(String producerKey) {
+        // Parse off the producerId
+        int p = producerKey.lastIndexOf(":");
+        if (p >= 0) {
+            value = Long.parseLong(producerKey.substring(p + 1));
+            producerKey = producerKey.substring(0, p);
+        }
+        setProducerSessionKey(producerKey);
+    }
+
+    public JmsSessionId getParentId() {
+        if (parentId == null) {
+            parentId = new JmsSessionId(this);
+        }
+        return parentId;
+    }
+
+    private void setProducerSessionKey(String sessionKey) {
+        // Parse off the value of the session Id
+        int p = sessionKey.lastIndexOf(":");
+        if (p >= 0) {
+            sessionId = Long.parseLong(sessionKey.substring(p + 1));
+            sessionKey = sessionKey.substring(0, p);
+        }
+
+        // The rest is the value of the connection Id.
+        connectionId = sessionKey;
+
+        parentId = new JmsSessionId(connectionId, sessionId);
+    }
+
+    public String getConnectionId() {
+        return connectionId;
+    }
+
+    public long getValue() {
+        return value;
+    }
+
+    public long getSessionId() {
+        return sessionId;
+    }
+
+    @Override
+    public String toString() {
+        if (key == null) {
+            key = connectionId + ":" + sessionId + ":" + value;
+        }
+        return key;
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) {
+            hashCode = connectionId.hashCode() ^ (int)sessionId ^ (int)value;
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || o.getClass() != JmsProducerId.class) {
+            return false;
+        }
+        JmsProducerId id = (JmsProducerId)o;
+        return sessionId == id.sessionId && value == id.value && connectionId.equals(id.connectionId);
+    }
+
+    @Override
+    public int compareTo(JmsProducerId other) {
+        return toString().compareTo(other.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerInfo.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerInfo.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerInfo.java
new file mode 100644
index 0000000..f9fd9b3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/meta/JmsProducerInfo.java
@@ -0,0 +1,103 @@
+/**
+ * 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.jms.meta;
+
+import org.apache.qpid.jms.JmsDestination;
+import org.apache.qpid.jms.util.ToStringSupport;
+
+public final class JmsProducerInfo implements JmsResource, Comparable<JmsProducerInfo> {
+
+    protected final JmsProducerId producerId;
+    protected JmsDestination destination;
+
+    public JmsProducerInfo(JmsProducerId producerId) {
+        this.producerId = producerId;
+    }
+
+    public JmsProducerInfo(JmsSessionInfo sessionInfo, long producerId) {
+        this.producerId = new JmsProducerId(sessionInfo.getSessionId(), producerId);
+    }
+
+    public JmsProducerInfo copy() {
+        JmsProducerInfo info = new JmsProducerInfo(producerId);
+        copy(info);
+        return info;
+    }
+
+    public void copy(JmsProducerInfo info) {
+        info.destination = destination;
+    }
+
+    public JmsProducerId getProducerId() {
+        return producerId;
+    }
+
+    public JmsSessionId getParentId() {
+        return producerId.getParentId();
+    }
+
+    public JmsDestination getDestination() {
+        return destination;
+    }
+
+    public void setDestination(JmsDestination destination) {
+        this.destination = destination;
+    }
+
+    @Override
+    public String toString() {
+        return ToStringSupport.toString(this);
+    }
+
+    @Override
+    public int hashCode() {
+        return (producerId == null) ? 0 : producerId.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        JmsProducerInfo other = (JmsProducerInfo) obj;
+
+        if (producerId == null && other.producerId != null) {
+            return false;
+        } else if (!producerId.equals(other.producerId)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int compareTo(JmsProducerInfo other) {
+        return this.producerId.compareTo(other.producerId);
+    }
+
+    @Override
+    public void visit(JmsResourceVistor vistor) throws Exception {
+        vistor.processProducerInfo(this);
+    }
+}


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


[27/27] git commit: Initial drop of donated AMQP Client Code.

Posted by ta...@apache.org.
Initial drop of donated AMQP Client Code.

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

Branch: refs/heads/master
Commit: e4decdc1e5df9797915b5a892f59bc20134c969c
Parents: 99f60c2
Author: Timothy Bish <ta...@gmail.com>
Authored: Tue Sep 23 14:09:26 2014 -0400
Committer: Timothy Bish <ta...@gmail.com>
Committed: Tue Sep 23 14:09:26 2014 -0400

----------------------------------------------------------------------
 LICENSE                                         |  202 ++++
 README.md                                       |    5 +
 pom.xml                                         |  237 ++++
 qpid-jms-client/.gitignore                      |    3 +
 qpid-jms-client/pom.xml                         |  173 +++
 .../org/apache/qpid/jms/version.txt             |    1 +
 .../apache/qpid/jms/JmsClientProperties.java    |   36 +
 .../java/org/apache/qpid/jms/JmsConnection.java | 1128 +++++++++++++++++
 .../apache/qpid/jms/JmsConnectionFactory.java   |  664 ++++++++++
 .../apache/qpid/jms/JmsConnectionListener.java  |   62 +
 .../apache/qpid/jms/JmsConnectionMetaData.java  |  164 +++
 .../org/apache/qpid/jms/JmsDestination.java     |  189 +++
 .../qpid/jms/JmsDurableTopicSubscriber.java     |   47 +
 .../qpid/jms/JmsLocalTransactionContext.java    |  216 ++++
 .../qpid/jms/JmsMessageAvailableConsumer.java   |   45 +
 .../qpid/jms/JmsMessageAvailableListener.java   |   35 +
 .../org/apache/qpid/jms/JmsMessageConsumer.java |  509 ++++++++
 .../apache/qpid/jms/JmsMessageDispatcher.java   |   31 +
 .../org/apache/qpid/jms/JmsMessageProducer.java |  334 ++++++
 .../org/apache/qpid/jms/JmsPrefetchPolicy.java  |  181 +++
 .../main/java/org/apache/qpid/jms/JmsQueue.java |   49 +
 .../org/apache/qpid/jms/JmsQueueBrowser.java    |  264 ++++
 .../org/apache/qpid/jms/JmsQueueConnection.java |   48 +
 .../org/apache/qpid/jms/JmsQueueReceiver.java   |   59 +
 .../org/apache/qpid/jms/JmsQueueSender.java     |   78 ++
 .../org/apache/qpid/jms/JmsQueueSession.java    |  187 +++
 .../java/org/apache/qpid/jms/JmsSession.java    | 1002 ++++++++++++++++
 .../qpid/jms/JmsSslConnectionFactory.java       |   93 ++
 .../java/org/apache/qpid/jms/JmsSslContext.java |  100 ++
 .../org/apache/qpid/jms/JmsTemporaryQueue.java  |   62 +
 .../org/apache/qpid/jms/JmsTemporaryTopic.java  |   62 +
 .../main/java/org/apache/qpid/jms/JmsTopic.java |   49 +
 .../org/apache/qpid/jms/JmsTopicConnection.java |   43 +
 .../org/apache/qpid/jms/JmsTopicPublisher.java  |  100 ++
 .../org/apache/qpid/jms/JmsTopicSession.java    |  163 +++
 .../org/apache/qpid/jms/JmsTopicSubscriber.java |   70 ++
 .../apache/qpid/jms/JmsTransactionListener.java |   31 +
 .../apache/qpid/jms/JmsTxSynchronization.java   |   47 +
 .../jms/exceptions/IdConversionException.java   |   36 +
 .../JmsConnectionClosedException.java           |   47 +
 .../JmsConnectionFailedException.java           |   47 +
 .../jms/exceptions/JmsExceptionSupport.java     |  103 ++
 .../qpid/jms/exceptions/QpidJmsException.java   |   43 +
 .../qpid/jms/jndi/JNDIReferenceFactory.java     |  125 ++
 .../org/apache/qpid/jms/jndi/JNDIStorable.java  |  119 ++
 .../qpid/jms/jndi/JmsInitialContextFactory.java |  197 +++
 .../apache/qpid/jms/jndi/LazyCreateContext.java |   46 +
 .../apache/qpid/jms/jndi/NameParserImpl.java    |   35 +
 .../apache/qpid/jms/jndi/ReadOnlyContext.java   |  465 +++++++
 .../qpid/jms/message/JmsBytesMessage.java       |  831 +++++++++++++
 .../jms/message/JmsDefaultMessageFactory.java   |   94 ++
 .../jms/message/JmsInboundMessageDispatch.java  |   57 +
 .../apache/qpid/jms/message/JmsMapMessage.java  |  320 +++++
 .../org/apache/qpid/jms/message/JmsMessage.java |  643 ++++++++++
 .../qpid/jms/message/JmsMessageFactory.java     |  133 ++
 .../message/JmsMessagePropertyIntercepter.java  |  622 ++++++++++
 .../jms/message/JmsMessageTransformation.java   |  198 +++
 .../qpid/jms/message/JmsObjectMessage.java      |  111 ++
 .../jms/message/JmsOutboundMessageDispatch.java |   63 +
 .../qpid/jms/message/JmsStreamMessage.java      |  485 ++++++++
 .../apache/qpid/jms/message/JmsTextMessage.java |   68 ++
 .../message/facade/JmsBytesMessageFacade.java   |   54 +
 .../jms/message/facade/JmsMapMessageFacade.java |   90 ++
 .../jms/message/facade/JmsMessageFacade.java    |  357 ++++++
 .../message/facade/JmsObjectMessageFacade.java  |   67 ++
 .../message/facade/JmsStreamMessageFacade.java  |   76 ++
 .../message/facade/JmsTextMessageFacade.java    |   53 +
 .../defaults/JmsDefaultBytesMessageFacade.java  |   68 ++
 .../defaults/JmsDefaultMapMessageFacade.java    |   75 ++
 .../defaults/JmsDefaultMessageFacade.java       |  316 +++++
 .../defaults/JmsDefaultObjectMessageFacade.java |  105 ++
 .../defaults/JmsDefaultStreamMessageFacade.java |   85 ++
 .../defaults/JmsDefaultTextMessageFacade.java   |   62 +
 .../qpid/jms/meta/JmsAbstractResourceId.java    |   47 +
 .../apache/qpid/jms/meta/JmsConnectionId.java   |   76 ++
 .../apache/qpid/jms/meta/JmsConnectionInfo.java |  251 ++++
 .../org/apache/qpid/jms/meta/JmsConsumerId.java |  121 ++
 .../apache/qpid/jms/meta/JmsConsumerInfo.java   |  187 +++
 .../jms/meta/JmsDefaultResourceVisitor.java     |   51 +
 .../org/apache/qpid/jms/meta/JmsMessageId.java  |  109 ++
 .../org/apache/qpid/jms/meta/JmsProducerId.java |  123 ++
 .../apache/qpid/jms/meta/JmsProducerInfo.java   |  103 ++
 .../org/apache/qpid/jms/meta/JmsResource.java   |   35 +
 .../org/apache/qpid/jms/meta/JmsResourceId.java |   56 +
 .../apache/qpid/jms/meta/JmsResourceVistor.java |   38 +
 .../org/apache/qpid/jms/meta/JmsSessionId.java  |  100 ++
 .../apache/qpid/jms/meta/JmsSessionInfo.java    |   63 +
 .../apache/qpid/jms/meta/JmsTransactionId.java  |   81 ++
 .../qpid/jms/meta/JmsTransactionInfo.java       |   90 ++
 .../main/java/org/apache/qpid/jms/package.html  |   25 +
 .../qpid/jms/provider/AbstractProvider.java     |   93 ++
 .../apache/qpid/jms/provider/AsyncResult.java   |   47 +
 .../jms/provider/DefaultProviderListener.java   |   52 +
 .../org/apache/qpid/jms/provider/Provider.java  |  292 +++++
 .../jms/provider/ProviderClosedException.java   |   28 +
 .../qpid/jms/provider/ProviderConstants.java    |   43 +
 .../qpid/jms/provider/ProviderFactory.java      |  110 ++
 .../qpid/jms/provider/ProviderFuture.java       |  109 ++
 .../qpid/jms/provider/ProviderListener.java     |  103 ++
 .../qpid/jms/provider/ProviderWrapper.java      |  179 +++
 .../jms/provider/amqp/AbstractAmqpResource.java |  242 ++++
 .../provider/amqp/AmqpAnonymousProducer.java    |  192 +++
 .../qpid/jms/provider/amqp/AmqpConnection.java  |  285 +++++
 .../qpid/jms/provider/amqp/AmqpConsumer.java    |  461 +++++++
 .../jms/provider/amqp/AmqpFixedProducer.java    |  351 ++++++
 .../qpid/jms/provider/amqp/AmqpJMSVendor.java   |  159 +++
 .../jms/provider/amqp/AmqpJmsNoLocalType.java   |   44 +
 .../jms/provider/amqp/AmqpJmsSelectorType.java  |   42 +
 .../qpid/jms/provider/amqp/AmqpProducer.java    |   93 ++
 .../qpid/jms/provider/amqp/AmqpProvider.java    |  821 +++++++++++++
 .../jms/provider/amqp/AmqpProviderFactory.java  |   57 +
 .../jms/provider/amqp/AmqpQueueBrowser.java     |  127 ++
 .../qpid/jms/provider/amqp/AmqpResource.java    |  130 ++
 .../provider/amqp/AmqpSaslAuthenticator.java    |  127 ++
 .../qpid/jms/provider/amqp/AmqpSession.java     |  281 +++++
 .../qpid/jms/provider/amqp/AmqpSslProvider.java |   47 +
 .../provider/amqp/AmqpSslProviderFactory.java   |   32 +
 .../provider/amqp/AmqpTemporaryDestination.java |  132 ++
 .../provider/amqp/AmqpTransactionContext.java   |  269 +++++
 .../provider/amqp/AmqpTransferTagGenerator.java |  103 ++
 .../amqp/message/AmqpJmsBytesMessageFacade.java |  144 +++
 .../amqp/message/AmqpJmsMapMessageFacade.java   |  154 +++
 .../amqp/message/AmqpJmsMessageBuilder.java     |  107 ++
 .../amqp/message/AmqpJmsMessageFacade.java      |  674 +++++++++++
 .../amqp/message/AmqpJmsMessageFactory.java     |  130 ++
 .../AmqpJmsMessagePropertyIntercepter.java      |  377 ++++++
 .../message/AmqpJmsObjectMessageFacade.java     |  124 ++
 .../message/AmqpJmsStreamMessageFacade.java     |  163 +++
 .../amqp/message/AmqpJmsTextMessageFacade.java  |  156 +++
 .../amqp/message/AmqpMessageIdHelper.java       |  270 +++++
 .../amqp/message/AmqpMessageSupport.java        |  169 +++
 .../amqp/message/AmqpObjectTypeDelegate.java    |   50 +
 .../message/AmqpSerializedObjectDelegate.java   |  101 ++
 .../amqp/message/AmqpTypedObjectDelegate.java   |  103 ++
 .../jms/provider/failover/FailoverProvider.java |  857 +++++++++++++
 .../failover/FailoverProviderFactory.java       |   56 +
 .../jms/provider/failover/FailoverUriPool.java  |  196 +++
 .../apache/qpid/jms/sasl/AbstractMechanism.java |   75 ++
 .../qpid/jms/sasl/AnonymousMechanism.java       |   43 +
 .../jms/sasl/AnonymousMechanismFactory.java     |   28 +
 .../apache/qpid/jms/sasl/CramMD5Mechanism.java  |   86 ++
 .../qpid/jms/sasl/CramMD5MechanismFactory.java  |   28 +
 .../org/apache/qpid/jms/sasl/Mechanism.java     |  125 ++
 .../apache/qpid/jms/sasl/MechanismFactory.java  |   31 +
 .../apache/qpid/jms/sasl/PlainMechanism.java    |   62 +
 .../qpid/jms/sasl/PlainMechanismFactory.java    |   28 +
 .../qpid/jms/sasl/SaslMechanismFinder.java      |  108 ++
 .../qpid/jms/transports/RawTcpTransport.java    |  383 ++++++
 .../qpid/jms/transports/SslTransport.java       |   59 +
 .../jms/transports/TcpBufferedInputStream.java  |  139 +++
 .../jms/transports/TcpBufferedOutputStream.java |  126 ++
 .../qpid/jms/transports/TcpTransport.java       |  270 +++++
 .../apache/qpid/jms/transports/Transport.java   |   87 ++
 .../qpid/jms/transports/TransportListener.java  |   48 +
 .../qpid/jms/util/AbstractMessageQueue.java     |  129 ++
 .../ClassLoadingAwareObjectInputStream.java     |  150 +++
 .../org/apache/qpid/jms/util/FactoryFinder.java |  210 ++++
 .../apache/qpid/jms/util/FifoMessageQueue.java  |   97 ++
 .../qpid/jms/util/IOExceptionSupport.java       |   47 +
 .../org/apache/qpid/jms/util/IdGenerator.java   |  228 ++++
 .../apache/qpid/jms/util/InetAddressUtil.java   |   57 +
 .../org/apache/qpid/jms/util/MessageQueue.java  |  131 ++
 .../qpid/jms/util/PriorityMessageQueue.java     |  144 +++
 .../org/apache/qpid/jms/util/PropertyUtil.java  |  486 ++++++++
 .../org/apache/qpid/jms/util/StopWatch.java     |   79 ++
 .../apache/qpid/jms/util/ThreadPoolUtils.java   |  190 +++
 .../org/apache/qpid/jms/util/TimeUtils.java     |   73 ++
 .../apache/qpid/jms/util/ToStringSupport.java   |  125 ++
 .../qpid/jms/util/TypeConversionSupport.java    |  180 +++
 .../org/apache/qpid/jms/util/URISupport.java    |  430 +++++++
 .../services/org/apache/qpid/jms/provider/amqp  |   17 +
 .../org/apache/qpid/jms/provider/amqp+nio       |   17 +
 .../org/apache/qpid/jms/provider/amqp+nio+ssl   |   17 +
 .../org/apache/qpid/jms/provider/amqp+ssl       |   17 +
 .../services/org/apache/qpid/jms/provider/amqps |   17 +
 .../org/apache/qpid/jms/provider/failover       |   17 +
 .../services/org/apache/qpid/jms/sasl/ANONYMOUS |   17 +
 .../services/org/apache/qpid/jms/sasl/CRAM-MD5  |   17 +
 .../services/org/apache/qpid/jms/sasl/PLAIN     |   17 +
 .../integration/ConnectionIntegrationTest.java  |   66 +
 .../jms/integration/IntegrationTestFixture.java |   48 +
 .../jms/integration/MessageIntegrationTest.java |  957 +++++++++++++++
 .../jms/integration/SenderIntegrationTest.java  |  379 ++++++
 .../qpid/jms/message/JmsBytesMessageTest.java   |  666 ++++++++++
 .../qpid/jms/message/JmsMapMessageTest.java     |  911 ++++++++++++++
 .../apache/qpid/jms/message/JmsMessageTest.java |  944 +++++++++++++++
 .../qpid/jms/message/JmsObjectMessageTest.java  |  260 ++++
 .../qpid/jms/message/JmsStreamMessageTest.java  | 1133 ++++++++++++++++++
 .../qpid/jms/message/JmsTextMessageTest.java    |  138 +++
 .../amqp/message/AmqpMessageIdHelperTest.java   |  496 ++++++++
 .../apache/qpid/jms/test/QpidJmsTestCase.java   |   98 ++
 ...ractFrameFieldAndPayloadMatchingHandler.java |  112 ++
 .../qpid/jms/test/testpeer/AmqpDataFramer.java  |   64 +
 .../jms/test/testpeer/AmqpPeerRunnable.java     |   25 +
 .../testpeer/CompositeAmqpPeerRunnable.java     |   49 +
 .../jms/test/testpeer/DescriptorMatcher.java    |   53 +
 .../qpid/jms/test/testpeer/FrameHandler.java    |   27 +
 .../jms/test/testpeer/FrameMatchingHandler.java |  146 +++
 .../qpid/jms/test/testpeer/FrameSender.java     |   63 +
 .../qpid/jms/test/testpeer/FrameType.java       |   22 +
 .../FrameWithNoPayloadMatchingHandler.java      |   49 +
 .../FrameWithPayloadMatchingHandler.java        |   64 +
 .../apache/qpid/jms/test/testpeer/Handler.java  |   28 +
 .../qpid/jms/test/testpeer/HeaderHandler.java   |   24 +
 .../jms/test/testpeer/HeaderHandlerImpl.java    |   74 ++
 .../jms/test/testpeer/ListDescribedType.java    |   66 +
 .../jms/test/testpeer/MapDescribedType.java     |   46 +
 .../qpid/jms/test/testpeer/TestAmqpPeer.java    |  621 ++++++++++
 .../jms/test/testpeer/TestAmqpPeerRunner.java   |  153 +++
 .../qpid/jms/test/testpeer/TestFrameParser.java |  375 ++++++
 .../qpid/jms/test/testpeer/ValueProvider.java   |   28 +
 .../test/testpeer/describedtypes/Accepted.java  |   54 +
 .../testpeer/describedtypes/AttachFrame.java    |  152 +++
 .../testpeer/describedtypes/BeginFrame.java     |  110 ++
 .../testpeer/describedtypes/CloseFrame.java     |   61 +
 .../testpeer/describedtypes/DetachFrame.java    |   75 ++
 .../describedtypes/DispositionFrame.java        |   96 ++
 .../test/testpeer/describedtypes/EndFrame.java  |   61 +
 .../test/testpeer/describedtypes/FlowFrame.java |  131 ++
 .../test/testpeer/describedtypes/Modified.java  |   75 ++
 .../test/testpeer/describedtypes/OpenFrame.java |  124 ++
 .../test/testpeer/describedtypes/Rejected.java  |   61 +
 .../test/testpeer/describedtypes/Released.java  |   54 +
 .../describedtypes/SaslChallengeFrame.java      |   61 +
 .../testpeer/describedtypes/SaslInitFrame.java  |   75 ++
 .../describedtypes/SaslMechanismsFrame.java     |   61 +
 .../describedtypes/SaslOutcomeFrame.java        |   68 ++
 .../describedtypes/SaslResponseFrame.java       |   61 +
 .../test/testpeer/describedtypes/Source.java    |  131 ++
 .../test/testpeer/describedtypes/Target.java    |  103 ++
 .../testpeer/describedtypes/TransferFrame.java  |  131 ++
 .../testpeer/describedtypes/generate-frames.xsl |  154 +++
 .../sections/AmqpValueDescribedType.java        |   48 +
 .../ApplicationPropertiesDescribedType.java     |   45 +
 .../sections/DataDescribedType.java             |   54 +
 .../sections/HeaderDescribedType.java           |   89 ++
 .../MessageAnnotationsDescribedType.java        |   46 +
 .../sections/PropertiesDescribedType.java       |  145 +++
 .../sections/generate-list-sections.xsl         |  146 +++
 .../test/testpeer/matchers/AttachMatcher.java   |  231 ++++
 .../test/testpeer/matchers/BeginMatcher.java    |  159 +++
 .../test/testpeer/matchers/CloseMatcher.java    |   75 ++
 .../test/testpeer/matchers/DetachMatcher.java   |   99 ++
 .../testpeer/matchers/DispositionMatcher.java   |  135 +++
 .../jms/test/testpeer/matchers/EndMatcher.java  |   75 ++
 .../jms/test/testpeer/matchers/FlowMatcher.java |  195 +++
 .../jms/test/testpeer/matchers/OpenMatcher.java |  183 +++
 .../testpeer/matchers/SaslChallengeMatcher.java |   75 ++
 .../test/testpeer/matchers/SaslInitMatcher.java |   99 ++
 .../matchers/SaslMechanismsMatcher.java         |   75 ++
 .../testpeer/matchers/SaslOutcomeMatcher.java   |   87 ++
 .../testpeer/matchers/SaslResponseMatcher.java  |   75 ++
 .../test/testpeer/matchers/TransferMatcher.java |  195 +++
 .../testpeer/matchers/generate-matchers.xsl     |  169 +++
 .../sections/AbstractMessageSectionMatcher.java |  138 +++
 .../ApplicationPropertiesSectionMatcher.java    |   53 +
 .../MessageAnnotationsSectionMatcher.java       |   75 ++
 .../sections/MessageHeaderSectionMatcher.java   |  118 ++
 .../sections/MessageListSectionMatcher.java     |   58 +
 .../sections/MessageMapSectionMatcher.java      |   55 +
 .../MessagePropertiesSectionMatcher.java        |  214 ++++
 .../TransferPayloadCompositeMatcher.java        |  224 ++++
 .../generate-message-section-matchers.xsl       |  166 +++
 .../matchers/types/EncodedAmqpTypeMatcher.java  |  114 ++
 .../matchers/types/EncodedAmqpValueMatcher.java |   56 +
 .../matchers/types/EncodedDataMatcher.java      |   58 +
 .../apache/qpid/jms/util/URISupportTest.java    |  216 ++++
 qpid-jms-client/src/test/resources/keystore     |  Bin 0 -> 3705 bytes
 .../src/test/resources/log4j.properties         |   38 +
 qpid-jms-discovery/.gitignore                   |    1 +
 qpid-jms-discovery/pom.xml                      |   93 ++
 .../jms/provider/discovery/DiscoveryAgent.java  |   63 +
 .../discovery/DiscoveryAgentFactory.java        |  112 ++
 .../jms/provider/discovery/DiscoveryEvent.java  |   45 +
 .../provider/discovery/DiscoveryListener.java   |   40 +
 .../provider/discovery/DiscoveryProvider.java   |  139 +++
 .../discovery/DiscoveryProviderFactory.java     |   65 +
 .../multicast/MulticastDiscoveryAgent.java      |  391 ++++++
 .../MulticastDiscoveryAgentFactory.java         |   57 +
 .../discovery/multicast/PacketParser.java       |   55 +
 .../multicast/PacketParserFactory.java          |  110 ++
 .../multicast/parsers/ActiveMQPacketParser.java |   77 ++
 .../parsers/ActiveMQPacketParserFactory.java    |   42 +
 .../apache/qpid/jms/provider/agents/multicast   |   17 +
 .../provider/agents/multicast-parsers/activemq  |   17 +
 .../org/apache/qpid/jms/provider/discovery      |   17 +
 qpid-jms-examples/.gitignore                    |    1 +
 qpid-jms-examples/pom.xml                       |   37 +
 .../java/org/apache/qpid/jms/example/Drain.java |  139 +++
 .../java/org/apache/qpid/jms/example/Spout.java |  132 ++
 qpid-jms-interop-tests/.gitignore               |    1 +
 qpid-jms-interop-tests/README.md                |    3 +
 qpid-jms-interop-tests/pom.xml                  |   37 +
 .../qpid-jms-activemq-tests/.gitignore          |    1 +
 .../qpid-jms-activemq-tests/pom.xml             |  116 ++
 .../jms/JmsConnectionCloseVariationsTest.java   |   68 ++
 .../qpid/jms/JmsConnectionClosedTest.java       |  103 ++
 .../JmsConnectionConcurrentCloseCallsTest.java  |   95 ++
 .../qpid/jms/JmsConnectionFactoryTest.java      |  118 ++
 .../qpid/jms/JmsConnectionFailedTest.java       |   60 +
 .../org/apache/qpid/jms/JmsConnectionTest.java  |  144 +++
 .../qpid/jms/JmsMessageIntegrityTest.java       |  497 ++++++++
 .../apache/qpid/jms/JmsQueueConnectionTest.java |   81 ++
 .../apache/qpid/jms/JmsSSLConnectionTest.java   |   92 ++
 .../apache/qpid/jms/JmsSessionClosedTest.java   |  243 ++++
 .../apache/qpid/jms/JmsSessionFailedTest.java   |   62 +
 .../org/apache/qpid/jms/JmsSessionTest.java     |   82 ++
 .../apache/qpid/jms/JmsTopicConnectionTest.java |   81 ++
 .../qpid/jms/bench/ConsumeFromAMQPTest.java     |  236 ++++
 .../qpid/jms/bench/ProduceToAMQPTest.java       |  169 +++
 .../qpid/jms/bench/ProduceToOpenWireTest.java   |  129 ++
 .../jms/bench/ProducerAndConsumerBench.java     |  202 ++++
 .../qpid/jms/consumer/JmsAutoAckTest.java       |  100 ++
 .../qpid/jms/consumer/JmsClientAckTest.java     |  361 ++++++
 .../JmsConsumerPriorityDispatchTest.java        |  123 ++
 .../JmsCreateResourcesInOnMessageTest.java      |   94 ++
 .../jms/consumer/JmsDurableSubscriberTest.java  |  143 +++
 .../consumer/JmsMessageConsumerClosedTest.java  |   89 ++
 .../consumer/JmsMessageConsumerFailedTest.java  |   65 +
 .../jms/consumer/JmsMessageConsumerTest.java    |  467 ++++++++
 .../qpid/jms/consumer/JmsMessageGroupTest.java  |   89 ++
 .../qpid/jms/consumer/JmsQueueBrowserTest.java  |  140 +++
 .../qpid/jms/consumer/JmsZeroPrefetchTest.java  |  110 ++
 .../jms/destinations/JmsTemporaryQueueTest.java |   49 +
 .../jms/destinations/JmsTemporaryTopicTest.java |   52 +
 .../jms/discovery/JmsAmqpDiscoveryTest.java     |  165 +++
 .../jms/discovery/JmsDiscoveryProviderTest.java |  107 ++
 .../qpid/jms/failover/FailoverProviderTest.java |   92 ++
 .../qpid/jms/failover/JmsFailoverTest.java      |  283 +++++
 .../jms/failover/JmsOfflineBehaviorTests.java   |  196 +++
 .../apache/qpid/jms/joram/ActiveMQAdmin.java    |  179 +++
 .../org/apache/qpid/jms/joram/JoramJmsTest.java |   71 ++
 .../jms/producer/JmsAnonymousProducerTest.java  |   93 ++
 .../producer/JmsMessageProducerClosedTest.java  |  133 ++
 .../producer/JmsMessageProducerFailedTest.java  |   65 +
 .../jms/producer/JmsMessageProducerTest.java    |  193 +++
 .../producer/JmsProduceMessageTypesTest.java    |  171 +++
 .../qpid/jms/producer/JmsQueueSenderTest.java   |   54 +
 .../jms/producer/JmsTopicPublisherTest.java     |   54 +
 .../qpid/jms/support/AmqpTestSupport.java       |  145 +++
 .../qpid/jms/support/QpidJmsTestSupport.java    |  447 +++++++
 .../java/org/apache/qpid/jms/support/Wait.java  |   48 +
 .../transactions/JmsTransactedConsumerTest.java |  208 ++++
 .../transactions/JmsTransactedProducerTest.java |   94 ++
 .../transactions/JmsTransactedSessionTest.java  |   98 ++
 .../JmsLargeMessageSendRecvTimedTest.java       |  114 ++
 .../src/test/resources/keystore                 |  Bin 0 -> 3705 bytes
 .../src/test/resources/log4j.properties         |   41 +
 .../src/test/resources/provider.properties      |   20 +
 .../src/test/resources/test.properties          |   17 +
 350 files changed, 51545 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..48ddf56
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+QpidJMS
+==========
+
+The QpidJMS project provides a JMS based client that uses the AMQP v1.0 protocol.
+

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..2035569
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>14</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.qpid</groupId>
+  <artifactId>qpid-jms-parent</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <name>QpidJMS</name>
+  <inceptionYear>2013</inceptionYear>
+  <url>https://qpid.apache.org</url>
+
+  <description>
+      QpidJMS is a JMS framework featuring support for AMQP v1.0
+  </description>
+
+  <prerequisites>
+    <maven>3.0.4</maven>
+  </prerequisites>
+
+  <properties>
+    <source-version>1.7</source-version>
+    <target-version>1.7</target-version>
+
+    <!-- Dependency Versions for this Project -->
+    <junit-version>4.11</junit-version>
+    <slf4j-version>1.7.7</slf4j-version>
+    <hawtbuf-version>1.11</hawtbuf-version>
+    <activemq-version>5.11-SNAPSHOT</activemq-version>
+    <apollo-version>1.7</apollo-version>
+    <proton-version>1.0-SNAPSHOT</proton-version>
+    <fuse-joram-tests-version>1.0</fuse-joram-tests-version>
+    <jetty-version>8.1.15.v20140411</jetty-version>
+    <vertex-version>2.0.2-final</vertex-version>
+    <mockito-version>1.9.5</mockito-version>
+    <hamcrest-version>1.3</hamcrest-version>
+
+    <!-- Maven Plugin Version for this Project -->
+    <maven-surefire-plugin-version>2.16</maven-surefire-plugin-version>
+    <maven-assembly-plugin-version>2.4</maven-assembly-plugin-version>
+    <maven-release-plugin-version>2.4.1</maven-release-plugin-version>
+    <maven-eclipse-plugin-version>2.9</maven-eclipse-plugin-version>
+    <maven-idea-plugin-version>2.5</maven-idea-plugin-version>
+    <maven-compiler-plugin-version>3.1</maven-compiler-plugin-version>
+    <findbugs-maven-plugin-version>3.0.0</findbugs-maven-plugin-version>
+
+    <!-- Test properties -->
+    <maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>
+    <proton.trace.frames>false</proton.trace.frames>
+
+    <!-- surefire forked jvm arguments -->
+    <argLine>-Xmx2g -enableassertions</argLine>
+  </properties>
+
+  <issueManagement>
+    <url>https://issues.apache.org/jira/browse/QPIDJMS</url>
+    <system>JIRA</system>
+  </issueManagement>
+
+  <scm>
+    <connection>scm:git:http://git-wip-us.apache.org/repos/asf/qpid-jms.git</connection>
+    <developerConnection>scm:git:https://git-wip-us.apache.org/repos/asf/qpid-jms.git</developerConnection>
+    <url>https://git-wip-us.apache.org/repos/asf?p=qpid-jms.git</url>
+    <tag>HEAD</tag>
+  </scm>
+
+  <modules>
+    <module>qpid-jms-client</module>
+    <module>qpid-jms-discovery</module>
+    <module>qpid-jms-interop-tests</module>
+    <module>qpid-jms-examples</module>
+  </modules>
+
+  <dependencyManagement>
+    <dependencies>
+      <!-- =============================== -->
+      <!-- Internal QpidJMS Dependencies -->
+      <!-- =============================== -->
+      <dependency>
+        <groupId>org.apache.qpid</groupId>
+        <artifactId>qpid-jms-client</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.qpid</groupId>
+        <artifactId>qpid-jms-discovery</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.qpid</groupId>
+        <artifactId>proton-jms</artifactId>
+        <version>${proton-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-jms_1.1_spec</artifactId>
+        <version>1.1.1</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-j2ee-management_1.1_spec</artifactId>
+        <version>1.0.1</version>
+      </dependency>
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>${junit-version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-all</artifactId>
+        <version>${mockito-version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.hamcrest</groupId>
+        <artifactId>hamcrest-all</artifactId>
+        <version>${hamcrest-version}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>${slf4j-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-log4j12</artifactId>
+        <version>${slf4j-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.fusesource.hawtbuf</groupId>
+        <artifactId>hawtbuf</artifactId>
+        <version>${hawtbuf-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.activemq</groupId>
+        <artifactId>apollo-selector</artifactId>
+        <version>${apollo-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.vertx</groupId>
+        <artifactId>vertx-core</artifactId>
+        <version>${vertex-version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.vertx</groupId>
+        <artifactId>vertx-platform</artifactId>
+        <version>${vertex-version}</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <build>
+    <defaultGoal>install</defaultGoal>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>${maven-surefire-plugin-version}</version>
+          <configuration>
+            <redirectTestOutputToFile>${maven.test.redirectTestOutputToFile}</redirectTestOutputToFile>
+            <forkCount>1</forkCount>
+            <reuseForks>true</reuseForks>
+            <systemPropertyVariables>
+                <java.awt.headless>true</java.awt.headless>
+            </systemPropertyVariables>
+            <failIfNoTests>false</failIfNoTests>
+            <environmentVariables>
+              <PN_TRACE_FRM>${proton.trace.frames}</PN_TRACE_FRM>
+            </environmentVariables>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-eclipse-plugin</artifactId>
+          <version>${maven-eclipse-plugin-version}</version>
+          <configuration>
+            <downloadSources>true</downloadSources>
+            <downloadJavadocs>true</downloadJavadocs>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-idea-plugin</artifactId>
+          <version>${maven-idea-plugin-version}</version>
+          <configuration>
+            <downloadSources>true</downloadSources>
+            <downloadJavadocs>true</downloadJavadocs>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>${maven-compiler-plugin-version}</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>${source-version}</source>
+          <target>${target-version}</target>
+          <optimize>true</optimize>
+          <debug>true</debug>
+          <showDeprecation>true</showDeprecation>
+          <showWarnings>true</showWarnings>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/.gitignore
----------------------------------------------------------------------
diff --git a/qpid-jms-client/.gitignore b/qpid-jms-client/.gitignore
new file mode 100644
index 0000000..073c9fa
--- /dev/null
+++ b/qpid-jms-client/.gitignore
@@ -0,0 +1,3 @@
+/target
+/target
+/target

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/pom.xml
----------------------------------------------------------------------
diff --git a/qpid-jms-client/pom.xml b/qpid-jms-client/pom.xml
new file mode 100644
index 0000000..54c605a
--- /dev/null
+++ b/qpid-jms-client/pom.xml
@@ -0,0 +1,173 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>qpid-jms-parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>qpid-jms-client</artifactId>
+  <packaging>jar</packaging>
+  <name>QpidJMS Client</name>
+  <description>The core JMS Client implementation</description>
+
+  <dependencies>
+    <!-- =================================== -->
+    <!-- Required Dependencies               -->
+    <!-- =================================== -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-jms_1.1_spec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.fusesource.hawtbuf</groupId>
+      <artifactId>hawtbuf</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>apollo-selector</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>proton-jms</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.vertx</groupId>
+      <artifactId>vertx-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.vertx</groupId>
+      <artifactId>vertx-platform</artifactId>
+    </dependency>
+
+    <!-- would be nice if we could make this dependency optional -->
+    <dependency>
+      <groupId>org.apache.geronimo.specs</groupId>
+      <artifactId>geronimo-j2ee-management_1.1_spec</artifactId>
+    </dependency>
+
+    <!-- =================================== -->
+    <!-- Testing Dependencies                -->
+    <!-- =================================== -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hamcrest</groupId>
+      <artifactId>hamcrest-all</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <!--  Joram JMS conformance tests -->
+    <dependency>
+      <groupId>org.fusesource.joram-jms-tests</groupId>
+      <artifactId>joram-jms-tests</artifactId>
+      <version>${fuse-joram-tests-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <!-- using it for Jetty's JNDI context to work /w Joram tests. -->
+      <groupId>org.eclipse.jetty.aggregate</groupId>
+      <artifactId>jetty-all-server</artifactId>
+      <version>${jetty-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-broker</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-kahadb-store</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-amqp</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-jaas</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.activemq</groupId>
+      <artifactId>activemq-spring</artifactId>
+      <version>${activemq-version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <resources>
+      <resource>
+        <directory>${project.basedir}/src/main/resources</directory>
+        <includes>
+          <include>**/*</include>
+        </includes>
+      </resource>
+      <resource>
+        <directory>${project.basedir}/src/main/filtered-resources</directory>
+        <filtering>true</filtering>
+        <includes>
+          <include>**/*</include>
+        </includes>
+      </resource>
+    </resources>
+  </build>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>findbugs-maven-plugin</artifactId>
+        <version>${findbugs-maven-plugin-version}</version>
+        <configuration>
+          <threshold>Normal</threshold>
+          <effort>Default</effort>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+
+</project>

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/filtered-resources/org/apache/qpid/jms/version.txt
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/filtered-resources/org/apache/qpid/jms/version.txt b/qpid-jms-client/src/main/filtered-resources/org/apache/qpid/jms/version.txt
new file mode 100644
index 0000000..f2ab45c
--- /dev/null
+++ b/qpid-jms-client/src/main/filtered-resources/org/apache/qpid/jms/version.txt
@@ -0,0 +1 @@
+${project.version}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsClientProperties.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsClientProperties.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsClientProperties.java
new file mode 100644
index 0000000..496ffd0
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/JmsClientProperties.java
@@ -0,0 +1,36 @@
+/**
+ * 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.jms;
+
+public class JmsClientProperties {
+
+    /**
+     * JMS-defined message property representing the user who sent a message.
+     */
+    public static final String JMSXUSERID = "JMSXUserID";
+
+    /**
+     * JMS-defined message property representing the group a message belongs to.
+     */
+    public static final String JMSXGROUPID = "JMSXGroupID";
+
+    /**
+     * JMS-defined message property representing the sequence number of a message within a group.
+     */
+    public static final String JMSXGROUPSEQ = "JMSXGroupSeq";
+
+}


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