You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by an...@apache.org on 2016/05/25 15:32:07 UTC

[3/4] activemq-artemis git commit: Adding JORAM Tests for AMQP with a few fixes around the protocol manager for JMS

Adding JORAM Tests for AMQP with a few fixes around the protocol manager for JMS


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/10dfe97e
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/10dfe97e
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/10dfe97e

Branch: refs/heads/master
Commit: 10dfe97ec01d163ba8cb8e60ce1c4e0774eb2662
Parents: b27033d
Author: Clebert Suconic <cl...@apache.org>
Authored: Tue May 24 18:09:16 2016 -0400
Committer: Clebert Suconic <cl...@apache.org>
Committed: Wed May 25 09:41:40 2016 -0400

----------------------------------------------------------------------
 .../apache/activemq/artemis/utils/FileUtil.java |  32 ++
 .../artemis/utils/SelectorTranslator.java       | 134 ++++++
 .../jms/client/ActiveMQQueueBrowser.java        |   1 +
 .../artemis/jms/client/ActiveMQSession.java     |   1 +
 .../artemis/jms/client/SelectorTranslator.java  | 134 ------
 .../management/impl/JMSQueueControlImpl.java    |   2 +-
 .../management/impl/JMSTopicControlImpl.java    |   2 +-
 .../jms/server/impl/JMSServerManagerImpl.java   |   2 +-
 .../proton/converter/ActiveMQJMSVendor.java     |   7 +-
 .../message/JMSMappingOutboundTransformer.java  |   2 +-
 .../plug/ProtonSessionIntegrationCallback.java  |  11 +-
 .../org/proton/plug/AMQPSessionCallback.java    |   2 +-
 .../context/AbstractProtonSessionContext.java   |   2 +-
 .../plug/context/ProtonTransactionHandler.java  |   2 +-
 .../test/minimalserver/MinimalSessionSPI.java   |   2 +-
 .../artemis/rest/queue/QueueConsumer.java       |   2 +-
 .../artemis/rest/queue/push/PushConsumer.java   |   2 +-
 .../artemis/tests/util/ActiveMQTestBase.java    |  25 +-
 tests/joram-tests/pom.xml                       |  12 +
 .../artemis/amqpJMS/ActiveMQAMQPAdmin.java      | 185 +++++++
 .../amqpJMS/JoramAMQPAggregationTest.java       |  86 ++++
 .../activemq/artemis/common/AbstractAdmin.java  | 275 +++++++++++
 .../artemis/common/SpawnedJMSServer.java        | 121 +++++
 .../artemis/common/testjndi/TestContext.java    | 482 +++++++++++++++++++
 .../common/testjndi/TestContextFactory.java     | 158 ++++++
 .../activemq/artemis/jms/AbstractAdmin.java     | 105 ----
 .../activemq/artemis/jms/ActiveMQAdmin.java     | 287 -----------
 .../activemq/artemis/jms/ActiveMQCoreAdmin.java | 150 ++++++
 .../activemq/artemis/jms/GenericAdmin.java      | 129 -----
 .../artemis/jms/JoramAggregationTest.java       |  82 ----
 .../artemis/jms/JoramCoreAggregationTest.java   |  83 ++++
 .../activemq/artemis/jms/SpawnedJMSServer.java  |  97 ----
 .../jtests/jms/framework/JMSTestCase.java       |  13 +-
 .../jtests/jms/framework/PTPTestCase.java       |  10 +-
 .../jtests/jms/framework/PubSubTestCase.java    |  11 +-
 .../jtests/jms/framework/UnifiedTestCase.java   |  14 +-
 .../src/test/resources/amqp_provider.properties |  28 ++
 .../src/test/resources/provider.properties      |   2 +-
 .../src/test/resources/test.properties          |   2 +-
 .../unit/jms/client/SelectorTranslatorTest.java |   2 +-
 40 files changed, 1791 insertions(+), 908 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/FileUtil.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/FileUtil.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/FileUtil.java
index 63ad15f..a6bf055 100644
--- a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/FileUtil.java
+++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/FileUtil.java
@@ -23,6 +23,8 @@ import java.nio.file.Files;
 import java.util.Arrays;
 import java.util.HashSet;
 
+import org.jboss.logging.Logger;
+
 import static java.nio.file.attribute.PosixFilePermission.GROUP_EXECUTE;
 import static java.nio.file.attribute.PosixFilePermission.GROUP_READ;
 import static java.nio.file.attribute.PosixFilePermission.GROUP_WRITE;
@@ -34,6 +36,8 @@ import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE;
 
 public class FileUtil {
 
+   private static final Logger logger = Logger.getLogger(FileUtil.class);
+
    public static void makeExec(File file) throws IOException {
       try {
          Files.setPosixFilePermissions(file.toPath(), new HashSet<>(Arrays.asList(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, OTHERS_READ, OTHERS_EXECUTE)));
@@ -43,4 +47,32 @@ public class FileUtil {
       }
    }
 
+
+   public static final boolean deleteDirectory(final File directory) {
+      if (directory.isDirectory()) {
+         String[] files = directory.list();
+         int num = 5;
+         int attempts = 0;
+         while (files == null && (attempts < num)) {
+            try {
+               Thread.sleep(100);
+            }
+            catch (InterruptedException e) {
+            }
+            files = directory.list();
+            attempts++;
+         }
+
+         for (String file : files) {
+            File f = new File(directory, file);
+            if (!deleteDirectory(f)) {
+               logger.warn("Failed to clean up file: " + f.getAbsolutePath());
+            }
+         }
+      }
+
+      return directory.delete();
+   }
+
+
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/SelectorTranslator.java
----------------------------------------------------------------------
diff --git a/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/SelectorTranslator.java b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/SelectorTranslator.java
new file mode 100644
index 0000000..5515926
--- /dev/null
+++ b/artemis-commons/src/main/java/org/apache/activemq/artemis/utils/SelectorTranslator.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class converts a JMS selector expression into an ActiveMQ Artemis core filter expression.
+ *
+ * JMS selector and ActiveMQ Artemis filters use the same syntax but have different identifiers.
+ *
+ * We basically just need to replace the JMS header and property Identifier names
+ * with the corresponding ActiveMQ Artemis field and header Identifier names.
+ *
+ * We must be careful not to substitute any literals, or identifiers whose name contains the name
+ * of one we want to substitute.
+ *
+ * This makes it less trivial than a simple search and replace.
+ */
+public class SelectorTranslator {
+
+   public static String convertToActiveMQFilterString(final String selectorString) {
+      if (selectorString == null) {
+         return null;
+      }
+
+      // First convert any JMS header identifiers
+
+      String filterString = SelectorTranslator.parse(selectorString, "JMSDeliveryMode", "AMQDurable");
+      filterString = SelectorTranslator.parse(filterString, "'PERSISTENT'", "'DURABLE'");
+      filterString = SelectorTranslator.parse(filterString, "'NON_PERSISTENT'", "'NON_DURABLE'");
+      filterString = SelectorTranslator.parse(filterString, "JMSPriority", "AMQPriority");
+      filterString = SelectorTranslator.parse(filterString, "JMSTimestamp", "AMQTimestamp");
+      filterString = SelectorTranslator.parse(filterString, "JMSMessageID", "AMQUserID");
+      filterString = SelectorTranslator.parse(filterString, "JMSExpiration", "AMQExpiration");
+
+      return filterString;
+
+   }
+
+   private static String parse(final String input, final String match, final String replace) {
+      final char quote = '\'';
+
+      boolean inQuote = false;
+
+      int matchPos = 0;
+
+      List<Integer> positions = new ArrayList<>();
+
+      boolean replaceInQuotes = match.charAt(0) == quote;
+
+      for (int i = 0; i < input.length(); i++) {
+         char c = input.charAt(i);
+
+         if (c == quote) {
+            inQuote = !inQuote;
+         }
+
+         if ((!inQuote || replaceInQuotes) && c == match.charAt(matchPos)) {
+            matchPos++;
+
+            if (matchPos == match.length()) {
+
+               boolean matched = true;
+
+               // Check that name is not part of another identifier name
+
+               // Check character after match
+               if (i < input.length() - 1 && Character.isJavaIdentifierPart(input.charAt(i + 1))) {
+                  matched = false;
+               }
+
+               // Check character before match
+               int posBeforeStart = i - match.length();
+
+               if (posBeforeStart >= 0 && Character.isJavaIdentifierPart(input.charAt(posBeforeStart))) {
+                  matched = false;
+               }
+
+               if (matched) {
+                  positions.add(i - match.length() + 1);
+               }
+
+               // check previous character too
+
+               matchPos = 0;
+            }
+         }
+         else {
+            matchPos = 0;
+         }
+      }
+
+      if (!positions.isEmpty()) {
+         StringBuffer buff = new StringBuffer();
+
+         int startPos = 0;
+
+         for (int pos : positions) {
+            String substr = input.substring(startPos, pos);
+
+            buff.append(substr);
+
+            buff.append(replace);
+
+            startPos = pos + match.length();
+         }
+
+         if (startPos < input.length()) {
+            buff.append(input.substring(startPos, input.length()));
+         }
+
+         return buff.toString();
+      }
+      else {
+         return input;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQQueueBrowser.java
----------------------------------------------------------------------
diff --git a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQQueueBrowser.java b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQQueueBrowser.java
index 4cf34ea..231a681 100644
--- a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQQueueBrowser.java
+++ b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQQueueBrowser.java
@@ -28,6 +28,7 @@ import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientConsumer;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
 import org.apache.activemq.artemis.api.core.client.ClientSession;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 
 /**
  * ActiveMQ Artemis implementation of a JMS QueueBrowser.

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQSession.java
----------------------------------------------------------------------
diff --git a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQSession.java b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQSession.java
index 50269f5..da2dd80 100644
--- a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQSession.java
+++ b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQSession.java
@@ -59,6 +59,7 @@ import org.apache.activemq.artemis.api.core.client.ClientProducer;
 import org.apache.activemq.artemis.api.core.client.ClientSession;
 import org.apache.activemq.artemis.api.core.client.ClientSession.AddressQuery;
 import org.apache.activemq.artemis.api.core.client.ClientSession.QueueQuery;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 
 /**
  * ActiveMQ Artemis implementation of a JMS Session.

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/SelectorTranslator.java
----------------------------------------------------------------------
diff --git a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/SelectorTranslator.java b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/SelectorTranslator.java
deleted file mode 100644
index 5dcd7c3..0000000
--- a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/SelectorTranslator.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.activemq.artemis.jms.client;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class converts a JMS selector expression into an ActiveMQ Artemis core filter expression.
- *
- * JMS selector and ActiveMQ Artemis filters use the same syntax but have different identifiers.
- *
- * We basically just need to replace the JMS header and property Identifier names
- * with the corresponding ActiveMQ Artemis field and header Identifier names.
- *
- * We must be careful not to substitute any literals, or identifiers whose name contains the name
- * of one we want to substitute.
- *
- * This makes it less trivial than a simple search and replace.
- */
-public class SelectorTranslator {
-
-   public static String convertToActiveMQFilterString(final String selectorString) {
-      if (selectorString == null) {
-         return null;
-      }
-
-      // First convert any JMS header identifiers
-
-      String filterString = SelectorTranslator.parse(selectorString, "JMSDeliveryMode", "AMQDurable");
-      filterString = SelectorTranslator.parse(filterString, "'PERSISTENT'", "'DURABLE'");
-      filterString = SelectorTranslator.parse(filterString, "'NON_PERSISTENT'", "'NON_DURABLE'");
-      filterString = SelectorTranslator.parse(filterString, "JMSPriority", "AMQPriority");
-      filterString = SelectorTranslator.parse(filterString, "JMSTimestamp", "AMQTimestamp");
-      filterString = SelectorTranslator.parse(filterString, "JMSMessageID", "AMQUserID");
-      filterString = SelectorTranslator.parse(filterString, "JMSExpiration", "AMQExpiration");
-
-      return filterString;
-
-   }
-
-   private static String parse(final String input, final String match, final String replace) {
-      final char quote = '\'';
-
-      boolean inQuote = false;
-
-      int matchPos = 0;
-
-      List<Integer> positions = new ArrayList<>();
-
-      boolean replaceInQuotes = match.charAt(0) == quote;
-
-      for (int i = 0; i < input.length(); i++) {
-         char c = input.charAt(i);
-
-         if (c == quote) {
-            inQuote = !inQuote;
-         }
-
-         if ((!inQuote || replaceInQuotes) && c == match.charAt(matchPos)) {
-            matchPos++;
-
-            if (matchPos == match.length()) {
-
-               boolean matched = true;
-
-               // Check that name is not part of another identifier name
-
-               // Check character after match
-               if (i < input.length() - 1 && Character.isJavaIdentifierPart(input.charAt(i + 1))) {
-                  matched = false;
-               }
-
-               // Check character before match
-               int posBeforeStart = i - match.length();
-
-               if (posBeforeStart >= 0 && Character.isJavaIdentifierPart(input.charAt(posBeforeStart))) {
-                  matched = false;
-               }
-
-               if (matched) {
-                  positions.add(i - match.length() + 1);
-               }
-
-               // check previous character too
-
-               matchPos = 0;
-            }
-         }
-         else {
-            matchPos = 0;
-         }
-      }
-
-      if (!positions.isEmpty()) {
-         StringBuffer buff = new StringBuffer();
-
-         int startPos = 0;
-
-         for (int pos : positions) {
-            String substr = input.substring(startPos, pos);
-
-            buff.append(substr);
-
-            buff.append(replace);
-
-            startPos = pos + match.length();
-         }
-
-         if (startPos < input.length()) {
-            buff.append(input.substring(startPos, input.length()));
-         }
-
-         return buff.toString();
-      }
-      else {
-         return input;
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSQueueControlImpl.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSQueueControlImpl.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSQueueControlImpl.java
index 2d6c46e..f41b85e 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSQueueControlImpl.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSQueueControlImpl.java
@@ -42,10 +42,10 @@ import org.apache.activemq.artemis.core.messagecounter.MessageCounter;
 import org.apache.activemq.artemis.core.messagecounter.impl.MessageCounterHelper;
 import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
 import org.apache.activemq.artemis.jms.client.ActiveMQMessage;
-import org.apache.activemq.artemis.jms.client.SelectorTranslator;
 import org.apache.activemq.artemis.jms.management.impl.openmbean.JMSOpenTypeSupport;
 import org.apache.activemq.artemis.jms.server.JMSServerManager;
 import org.apache.activemq.artemis.utils.Base64;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 import org.apache.activemq.artemis.utils.UUIDGenerator;
 import org.apache.activemq.artemis.utils.json.JSONArray;
 import org.apache.activemq.artemis.utils.json.JSONObject;

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSTopicControlImpl.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSTopicControlImpl.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSTopicControlImpl.java
index cfafe94..63d3d45 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSTopicControlImpl.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/management/impl/JMSTopicControlImpl.java
@@ -35,8 +35,8 @@ import org.apache.activemq.artemis.core.management.impl.MBeanInfoHelper;
 import org.apache.activemq.artemis.core.server.management.ManagementService;
 import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
 import org.apache.activemq.artemis.jms.client.ActiveMQMessage;
-import org.apache.activemq.artemis.jms.client.SelectorTranslator;
 import org.apache.activemq.artemis.jms.server.JMSServerManager;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 import org.apache.activemq.artemis.utils.json.JSONArray;
 import org.apache.activemq.artemis.utils.json.JSONObject;
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
index 5181731..85084c1 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
@@ -61,7 +61,6 @@ import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
 import org.apache.activemq.artemis.jms.client.ActiveMQDestination;
 import org.apache.activemq.artemis.jms.client.ActiveMQQueue;
 import org.apache.activemq.artemis.jms.client.ActiveMQTopic;
-import org.apache.activemq.artemis.jms.client.SelectorTranslator;
 import org.apache.activemq.artemis.jms.persistence.JMSStorageManager;
 import org.apache.activemq.artemis.jms.persistence.config.PersistedBindings;
 import org.apache.activemq.artemis.jms.persistence.config.PersistedConnectionFactory;
@@ -82,6 +81,7 @@ import org.apache.activemq.artemis.jms.server.management.JMSNotificationType;
 import org.apache.activemq.artemis.jms.server.management.impl.JMSManagementServiceImpl;
 import org.apache.activemq.artemis.jms.transaction.JMSTransactionDetail;
 import org.apache.activemq.artemis.spi.core.naming.BindingRegistry;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 import org.apache.activemq.artemis.utils.TimeAndCounterIDGenerator;
 import org.apache.activemq.artemis.utils.TypedProperties;
 import org.apache.activemq.artemis.utils.json.JSONArray;

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/ActiveMQJMSVendor.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/ActiveMQJMSVendor.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/ActiveMQJMSVendor.java
index 59e0edb..169c8e4 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/ActiveMQJMSVendor.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/ActiveMQJMSVendor.java
@@ -88,7 +88,13 @@ public class ActiveMQJMSVendor implements JMSVendor {
 
    @Override
    public void setJMSXGroupID(Message message, String s) {
+      try {
+         message.setStringProperty("_AMQ_GROUP_ID", s);
+      }
+      catch (Exception e) {
+         e.printStackTrace();
 
+      }
    }
 
    @Override
@@ -98,7 +104,6 @@ public class ActiveMQJMSVendor implements JMSVendor {
 
    @Override
    public void setJMSXDeliveryCount(Message message, long l) {
-
    }
 
    public ServerJMSMessage wrapMessage(int messageType, ServerMessage wrapped, int deliveryCount) {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/message/JMSMappingOutboundTransformer.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/message/JMSMappingOutboundTransformer.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/message/JMSMappingOutboundTransformer.java
index af8afc2..715faaa 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/message/JMSMappingOutboundTransformer.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/converter/message/JMSMappingOutboundTransformer.java
@@ -217,7 +217,7 @@ public class JMSMappingOutboundTransformer extends OutboundTransformer {
             String value = msg.getStringProperty(key);
             props.setUserId(new Binary(value.getBytes(StandardCharsets.UTF_8)));
          }
-         else if (key.startsWith("JMSXGroupID")) {
+         else if (key.startsWith("JMSXGroupID") || key.startsWith("_AMQ_GROUP_ID")) {
             String value = msg.getStringProperty(key);
             props.setGroupId(value);
             if (apMap == null) {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java
index 5b73acf..00f5e3f 100644
--- a/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java
+++ b/artemis-protocols/artemis-amqp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/proton/plug/ProtonSessionIntegrationCallback.java
@@ -27,6 +27,7 @@ import org.apache.activemq.artemis.core.server.impl.ServerConsumerImpl;
 import org.apache.activemq.artemis.core.transaction.Transaction;
 import org.apache.activemq.artemis.spi.core.remoting.Connection;
 import org.apache.activemq.artemis.spi.core.remoting.ReadyListener;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.transport.AmqpError;
 import org.apache.qpid.proton.amqp.transport.ErrorCondition;
@@ -158,11 +159,13 @@ public class ProtonSessionIntegrationCallback implements AMQPSessionCallback, Se
    @Override
    public Object createSender(ProtonPlugSender protonSender,
                               String queue,
-                              String filer,
+                              String filter,
                               boolean browserOnly) throws Exception {
       long consumerID = consumerIDGenerator.generateID();
 
-      ServerConsumer consumer = serverSession.createConsumer(consumerID, SimpleString.toSimpleString(queue), SimpleString.toSimpleString(filer), browserOnly);
+      filter = SelectorTranslator.convertToActiveMQFilterString(filter);
+
+      ServerConsumer consumer = serverSession.createConsumer(consumerID, SimpleString.toSimpleString(queue), SimpleString.toSimpleString(filter), browserOnly);
 
       // AMQP handles its own flow control for when it's started
       consumer.setStarted(true);
@@ -274,12 +277,12 @@ public class ProtonSessionIntegrationCallback implements AMQPSessionCallback, Se
    }
 
    @Override
-   public void rollbackCurrentTX() throws Exception {
+   public void rollbackCurrentTX(boolean lastMessageDelivered) throws Exception {
       //need to check here as this can be called if init fails
       if (serverSession != null) {
          recoverContext();
          try {
-            serverSession.rollback(false);
+            serverSession.rollback(lastMessageDelivered);
          }
          finally {
             resetContext();

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/AMQPSessionCallback.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/AMQPSessionCallback.java b/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/AMQPSessionCallback.java
index 630761f..bb53791 100644
--- a/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/AMQPSessionCallback.java
+++ b/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/AMQPSessionCallback.java
@@ -59,7 +59,7 @@ public interface AMQPSessionCallback {
 
    void commitCurrentTX() throws Exception;
 
-   void rollbackCurrentTX() throws Exception;
+   void rollbackCurrentTX(boolean lastMessageReceived) throws Exception;
 
    void close() throws Exception;
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/AbstractProtonSessionContext.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/AbstractProtonSessionContext.java b/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/AbstractProtonSessionContext.java
index 5b22944..a715feb 100644
--- a/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/AbstractProtonSessionContext.java
+++ b/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/AbstractProtonSessionContext.java
@@ -140,7 +140,7 @@ public abstract class AbstractProtonSessionContext extends ProtonInitializable i
       senders.clear();
       try {
          if (sessionSPI != null) {
-            sessionSPI.rollbackCurrentTX();
+            sessionSPI.rollbackCurrentTX(false);
             sessionSPI.close();
          }
       }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/ProtonTransactionHandler.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/ProtonTransactionHandler.java b/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/ProtonTransactionHandler.java
index e768bb4..ab89b5f 100644
--- a/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/ProtonTransactionHandler.java
+++ b/artemis-protocols/artemis-proton-plug/src/main/java/org/proton/plug/context/ProtonTransactionHandler.java
@@ -78,7 +78,7 @@ public class ProtonTransactionHandler implements ProtonDeliveryHandler {
             Discharge discharge = (Discharge) action;
             if (discharge.getFail()) {
                try {
-                  sessionSPI.rollbackCurrentTX();
+                  sessionSPI.rollbackCurrentTX(true);
                }
                catch (Exception e) {
                   throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.errorRollingbackCoordinator(e.getMessage());

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-protocols/artemis-proton-plug/src/test/java/org/proton/plug/test/minimalserver/MinimalSessionSPI.java
----------------------------------------------------------------------
diff --git a/artemis-protocols/artemis-proton-plug/src/test/java/org/proton/plug/test/minimalserver/MinimalSessionSPI.java b/artemis-protocols/artemis-proton-plug/src/test/java/org/proton/plug/test/minimalserver/MinimalSessionSPI.java
index 1e5839c..ebc85f1 100644
--- a/artemis-protocols/artemis-proton-plug/src/test/java/org/proton/plug/test/minimalserver/MinimalSessionSPI.java
+++ b/artemis-protocols/artemis-proton-plug/src/test/java/org/proton/plug/test/minimalserver/MinimalSessionSPI.java
@@ -120,7 +120,7 @@ public class MinimalSessionSPI implements AMQPSessionCallback {
    }
 
    @Override
-   public void rollbackCurrentTX() {
+   public void rollbackCurrentTX(boolean lastMessage) {
    }
 
    @Override

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/QueueConsumer.java
----------------------------------------------------------------------
diff --git a/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/QueueConsumer.java b/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/QueueConsumer.java
index 7776839..9ebc209 100644
--- a/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/QueueConsumer.java
+++ b/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/QueueConsumer.java
@@ -36,7 +36,7 @@ import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
 import org.apache.activemq.artemis.rest.ActiveMQRestLogger;
 import org.apache.activemq.artemis.rest.util.Constants;
 import org.apache.activemq.artemis.rest.util.LinkStrategy;
-import org.apache.activemq.artemis.jms.client.SelectorTranslator;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 
 /**
  * Auto-acknowleged consumer

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/push/PushConsumer.java
----------------------------------------------------------------------
diff --git a/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/push/PushConsumer.java b/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/push/PushConsumer.java
index ef47f0a..c8f17b3 100644
--- a/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/push/PushConsumer.java
+++ b/artemis-rest/src/main/java/org/apache/activemq/artemis/rest/queue/push/PushConsumer.java
@@ -20,9 +20,9 @@ import org.apache.activemq.artemis.api.core.ActiveMQException;
 import org.apache.activemq.artemis.api.core.client.ClientConsumer;
 import org.apache.activemq.artemis.api.core.client.ClientSession;
 import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
-import org.apache.activemq.artemis.jms.client.SelectorTranslator;
 import org.apache.activemq.artemis.rest.ActiveMQRestLogger;
 import org.apache.activemq.artemis.rest.queue.push.xml.PushRegistration;
+import org.apache.activemq.artemis.utils.SelectorTranslator;
 
 import java.util.ArrayList;
 import java.util.List;

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java
index 082a3aa..86d8cf6 100644
--- a/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/tests/util/ActiveMQTestBase.java
@@ -129,6 +129,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager
 import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager;
 import org.apache.activemq.artemis.spi.core.security.jaas.InVMLoginModule;
 import org.apache.activemq.artemis.utils.ActiveMQThreadFactory;
+import org.apache.activemq.artemis.utils.FileUtil;
 import org.apache.activemq.artemis.utils.OrderedExecutorFactory;
 import org.apache.activemq.artemis.utils.RandomUtil;
 import org.apache.activemq.artemis.utils.UUIDGenerator;
@@ -2045,29 +2046,7 @@ public abstract class ActiveMQTestBase extends Assert {
    }
 
    protected static final boolean deleteDirectory(final File directory) {
-      if (directory.isDirectory()) {
-         String[] files = directory.list();
-         int num = 5;
-         int attempts = 0;
-         while (files == null && (attempts < num)) {
-            try {
-               Thread.sleep(100);
-            }
-            catch (InterruptedException e) {
-            }
-            files = directory.list();
-            attempts++;
-         }
-
-         for (String file : files) {
-            File f = new File(directory, file);
-            if (!deleteDirectory(f)) {
-               log.warn("Failed to clean up file: " + f.getAbsolutePath());
-            }
-         }
-      }
-
-      return directory.delete();
+      return FileUtil.deleteDirectory(directory);
    }
 
    protected static final void copyRecursive(final File from, final File to) throws Exception {

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/tests/joram-tests/pom.xml
----------------------------------------------------------------------
diff --git a/tests/joram-tests/pom.xml b/tests/joram-tests/pom.xml
index f2896c2..332c256 100644
--- a/tests/joram-tests/pom.xml
+++ b/tests/joram-tests/pom.xml
@@ -46,6 +46,12 @@
       </dependency>
       <dependency>
          <groupId>org.apache.activemq</groupId>
+         <artifactId>artemis-amqp-protocol</artifactId>
+         <version>${project.version}</version>
+      </dependency>
+
+      <dependency>
+         <groupId>org.apache.activemq</groupId>
          <artifactId>artemis-cli</artifactId>
          <version>${project.version}</version>
       </dependency>
@@ -86,6 +92,12 @@
          <version>${project.version}</version>
          <scope>test</scope>
       </dependency>
+      <dependency>
+         <groupId>org.apache.qpid</groupId>
+         <artifactId>qpid-jms-client</artifactId>
+         <version>${qpid.jms.version}</version>
+         <scope>test</scope>
+      </dependency>
 
    </dependencies>
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/ActiveMQAMQPAdmin.java
----------------------------------------------------------------------
diff --git a/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/ActiveMQAMQPAdmin.java b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/ActiveMQAMQPAdmin.java
new file mode 100644
index 0000000..f307407
--- /dev/null
+++ b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/ActiveMQAMQPAdmin.java
@@ -0,0 +1,185 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.activemq.artemis.amqpJMS;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.Hashtable;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import org.apache.activemq.artemis.common.AbstractAdmin;
+import org.apache.activemq.artemis.common.testjndi.TestContextFactory;
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.JmsTopic;
+
+/**
+ *
+ */
+public class ActiveMQAMQPAdmin extends AbstractAdmin {
+
+   Context context;
+
+   {
+      // enableJMSFrameTracing();
+      try {
+         // Use the jetty JNDI context since it's mutable.
+         Hashtable<String, String> env = new Hashtable<>();
+         env.put("java.naming.factory.initial", TestContextFactory.class.getName());
+         env.put("java.naming.provider.url", "tcp://localhost:61616");
+         context = new InitialContext(env);
+      }
+      catch (NamingException e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   @SuppressWarnings("resource")
+   public static void enableJMSFrameTracing() {
+      try {
+         String outputStreamName = "amqp-trace.txt";
+         final PrintStream out = new PrintStream(new FileOutputStream(new File(outputStreamName)));
+         Handler handler = new Handler() {
+            @Override
+            public void publish(LogRecord r) {
+               out.println(String.format("%s:%s", r.getLoggerName(), r.getMessage()));
+            }
+
+            @Override
+            public void flush() {
+               out.flush();
+            }
+
+            @Override
+            public void close() throws SecurityException {
+               out.close();
+            }
+         };
+
+         Logger log = Logger.getLogger("FRM");
+         log.addHandler(handler);
+         log.setLevel(Level.FINEST);
+      }
+      catch (FileNotFoundException e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   @Override
+   public String getName() {
+      return getClass().getName();
+   }
+
+   @Override
+   public Context createContext() throws NamingException {
+      return context;
+   }
+
+   @Override
+   public void createQueue(String name) {
+      super.createQueue(name);
+      try {
+         context.bind(name, new JmsQueue("jms.queue." + name));
+      }
+      catch (NamingException e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   @Override
+   public void createTopic(String name) {
+      super.createTopic(name);
+      try {
+         context.bind(name, new JmsTopic("jms.topic." + name));
+      }
+      catch (NamingException e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   @Override
+   public void deleteQueue(String name) {
+      super.deleteQueue(name);
+      try {
+         context.unbind(name);
+      }
+      catch (NamingException e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   @Override
+   public void deleteTopic(String name) {
+      super.deleteTopic(name);
+      try {
+         context.unbind(name);
+      }
+      catch (NamingException e) {
+         throw new RuntimeException(e);
+      }
+   }
+
+   @Override
+   public void createConnectionFactory(String name) {
+      try {
+         final JmsConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:61616");
+         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/activemq-artemis/blob/10dfe97e/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/JoramAMQPAggregationTest.java
----------------------------------------------------------------------
diff --git a/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/JoramAMQPAggregationTest.java b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/JoramAMQPAggregationTest.java
new file mode 100644
index 0000000..246df36
--- /dev/null
+++ b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/amqpJMS/JoramAMQPAggregationTest.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.activemq.artemis.amqpJMS;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+import org.objectweb.jtests.jms.admin.Admin;
+import org.objectweb.jtests.jms.admin.AdminFactory;
+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.MessageTypeTest;
+import org.objectweb.jtests.jms.conform.message.headers.MessageHeaderTest;
+import org.objectweb.jtests.jms.conform.message.properties.JMSXPropertyTest;
+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.QueueBrowserTest;
+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.session.SessionTest;
+import org.objectweb.jtests.jms.conform.session.TopicSessionTest;
+import org.objectweb.jtests.jms.conform.session.UnifiedSessionTest;
+import org.objectweb.jtests.jms.conform.topic.TemporaryTopicTest;
+import org.objectweb.jtests.jms.framework.JMSTestCase;
+
+@RunWith(Suite.class)
+@SuiteClasses({TopicConnectionTest.class, ConnectionTest.class, MessageBodyTest.class, MessageDefaultTest.class,
+   MessageTypeTest.class, MessageHeaderTest.class, JMSXPropertyTest.class, MessagePropertyConversionTest.class, MessagePropertyTest.class,
+   QueueBrowserTest.class, TemporaryQueueTest.class, SelectorSyntaxTest.class, SelectorTest.class, QueueSessionTest.class, SessionTest.class,
+   TopicSessionTest.class, UnifiedSessionTest.class, TemporaryTopicTest.class,})
+public class JoramAMQPAggregationTest extends Assert {
+
+   /**
+    * Should be overridden
+    *
+    * @return
+    */
+   protected static Properties getProviderProperties() throws IOException {
+      Properties props = new Properties();
+      props.load(ClassLoader.getSystemResourceAsStream(JMSTestCase.getPropFileName()));
+      return props;
+   }
+
+   static Admin admin;
+
+   @BeforeClass
+   public static void setUpServer() throws Exception {
+      JMSTestCase.setPropFileName("amqp_provider.properties");
+      JMSTestCase.startServer = false;
+      // Admin step
+      // gets the provider administration wrapper...
+      Properties props = getProviderProperties();
+      admin = AdminFactory.getAdmin(props);
+      admin.startServer();
+   }
+
+   @AfterClass
+   public static void tearDownServer() throws Exception {
+      admin.stopServer();
+      JMSTestCase.startServer = true;
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/AbstractAdmin.java
----------------------------------------------------------------------
diff --git a/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/AbstractAdmin.java b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/AbstractAdmin.java
new file mode 100644
index 0000000..c9e249a
--- /dev/null
+++ b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/AbstractAdmin.java
@@ -0,0 +1,275 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.common;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration;
+import org.apache.activemq.artemis.api.core.TransportConfiguration;
+import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ClientRequestor;
+import org.apache.activemq.artemis.api.core.client.ClientSession;
+import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.apache.activemq.artemis.api.core.management.ManagementHelper;
+import org.apache.activemq.artemis.api.core.management.ResourceNames;
+import org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory;
+import org.apache.activemq.artemis.tests.util.SpawnedVMSupport;
+import org.junit.Assert;
+import org.objectweb.jtests.jms.admin.Admin;
+
+/**
+ * AbstractAdmin.
+ */
+public class AbstractAdmin implements Admin {
+
+   protected ClientSession clientSession;
+
+   protected ClientRequestor requestor;
+
+   protected boolean serverLifeCycleActive;
+
+   protected Process serverProcess;
+
+   protected ServerLocator serverLocator;
+
+   protected ClientSessionFactory sf;
+
+   // this is a constant to control if we should use a separate VM for the server.
+   public static final boolean spawnServer = false;
+
+   /**
+    * Determines whether to act or 'no-op' on serverStart() and
+    * serverStop(). This is used when testing combinations of client and
+    * servers with different versions.
+    */
+   private static final String SERVER_LIVE_CYCLE_PROPERTY = "org.apache.activemq.artemis.jms.ActiveMQAMQPAdmin.serverLifeCycle";
+
+   public AbstractAdmin() {
+      serverLifeCycleActive = Boolean.valueOf(System.getProperty(SERVER_LIVE_CYCLE_PROPERTY, "true"));
+
+   }
+
+   @Override
+   public String getName() {
+      return getClass().getName();
+   }
+
+   @Override
+   public void start() throws Exception {
+      serverLocator = ActiveMQClient.createServerLocatorWithoutHA(new TransportConfiguration(NettyConnectorFactory.class.getName()));
+      sf = serverLocator.createSessionFactory();
+      clientSession = sf.createSession(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword(), false, true, true, false, 1);
+      requestor = new ClientRequestor(clientSession, ActiveMQDefaultConfiguration.getDefaultManagementAddress());
+      clientSession.start();
+
+   }
+
+   @Override
+   public void stop() throws Exception {
+      requestor.close();
+
+      if (sf != null) {
+         sf.close();
+      }
+
+      if (serverLocator != null) {
+         serverLocator.close();
+      }
+
+      sf = null;
+      serverLocator = null;
+   }
+
+   @Override
+   public Context createContext() throws NamingException {
+      return new InitialContext();
+   }
+
+   @Override
+   public void createConnectionFactory(final String name) {
+      throw new RuntimeException("FIXME NYI createConnectionFactory");
+   }
+
+   @Override
+   public void deleteConnectionFactory(final String name) {
+      throw new RuntimeException("FIXME NYI deleteConnectionFactory");
+   }
+
+   @Override
+   public void createQueue(final String name) {
+      Boolean result;
+      try {
+         result = (Boolean) invokeSyncOperation(ResourceNames.JMS_SERVER, "createQueue", name, name);
+         Assert.assertEquals(true, result.booleanValue());
+      }
+      catch (Exception e) {
+         throw new IllegalStateException(e);
+      }
+   }
+
+   @Override
+   public void deleteQueue(final String name) {
+      Boolean result;
+      try {
+         result = (Boolean) invokeSyncOperation(ResourceNames.JMS_SERVER, "destroyQueue", name);
+         Assert.assertEquals(true, result.booleanValue());
+      }
+      catch (Exception e) {
+         throw new IllegalStateException(e);
+      }
+   }
+
+   @Override
+   public void createQueueConnectionFactory(final String name) {
+      createConnectionFactory(name);
+   }
+
+   @Override
+   public void deleteQueueConnectionFactory(final String name) {
+      deleteConnectionFactory(name);
+   }
+
+   @Override
+   public void createTopic(final String name) {
+      Boolean result;
+      try {
+         result = (Boolean) invokeSyncOperation(ResourceNames.JMS_SERVER, "createTopic", name, name);
+         Assert.assertEquals(true, result.booleanValue());
+      }
+      catch (Exception e) {
+         throw new IllegalStateException(e);
+      }
+   }
+
+   @Override
+   public void deleteTopic(final String name) {
+      Boolean result;
+      try {
+         result = (Boolean) invokeSyncOperation(ResourceNames.JMS_SERVER, "destroyTopic", name);
+         Assert.assertEquals(true, result.booleanValue());
+      }
+      catch (Exception e) {
+         throw new IllegalStateException(e);
+      }
+   }
+
+   @Override
+   public void createTopicConnectionFactory(final String name) {
+      createConnectionFactory(name);
+   }
+
+   @Override
+   public void deleteTopicConnectionFactory(final String name) {
+      deleteConnectionFactory(name);
+   }
+
+   @Override
+   public void startServer() throws Exception {
+      if (!serverLifeCycleActive) {
+         return;
+      }
+
+      if (spawnServer) {
+         String[] vmArgs = new String[]{};
+         serverProcess = SpawnedVMSupport.spawnVM(SpawnedJMSServer.class.getName(), vmArgs, false);
+         InputStreamReader isr = new InputStreamReader(serverProcess.getInputStream());
+
+         final BufferedReader br = new BufferedReader(isr);
+         String line = null;
+         while ((line = br.readLine()) != null) {
+            System.out.println("SERVER: " + line);
+            if ("OK".equals(line.trim())) {
+               new Thread() {
+                  @Override
+                  public void run() {
+                     try {
+                        String line1 = null;
+                        while ((line1 = br.readLine()) != null) {
+                           System.out.println("SERVER: " + line1);
+                        }
+                     }
+                     catch (Exception e) {
+                        e.printStackTrace();
+                     }
+                  }
+               }.start();
+               return;
+            }
+            else if ("KO".equals(line.trim())) {
+               // something went wrong with the server, destroy it:
+               serverProcess.destroy();
+               throw new IllegalStateException("Unable to start the spawned server :" + line);
+            }
+         }
+      }
+      else {
+         SpawnedJMSServer.startServer();
+      }
+   }
+
+   @Override
+   public void stopServer() throws Exception {
+      if (!serverLifeCycleActive) {
+         return;
+      }
+      if (spawnServer) {
+         OutputStreamWriter osw = new OutputStreamWriter(serverProcess.getOutputStream());
+         osw.write("STOP\n");
+         osw.flush();
+         int exitValue = serverProcess.waitFor();
+         if (exitValue != 0) {
+            serverProcess.destroy();
+         }
+      }
+      else {
+         SpawnedJMSServer.stopServer();
+      }
+   }
+
+   protected Object invokeSyncOperation(final String resourceName,
+                                        final String operationName,
+                                        final Object... parameters) throws Exception {
+      ClientMessage message = clientSession.createMessage(false);
+      ManagementHelper.putOperationInvocation(message, resourceName, operationName, parameters);
+      ClientMessage reply;
+      try {
+         reply = requestor.request(message, 3000);
+      }
+      catch (Exception e) {
+         throw new IllegalStateException("Exception while invoking " + operationName + " on " + resourceName, e);
+      }
+      if (reply == null) {
+         throw new IllegalStateException("no reply received when invoking " + operationName + " on " + resourceName);
+      }
+      if (!ManagementHelper.hasOperationSucceeded(reply)) {
+         throw new IllegalStateException("operation failed when invoking " + operationName +
+                                            " on " +
+                                            resourceName +
+                                            ": " +
+                                            ManagementHelper.getResult(reply));
+      }
+      return ManagementHelper.getResult(reply);
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/SpawnedJMSServer.java
----------------------------------------------------------------------
diff --git a/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/SpawnedJMSServer.java b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/SpawnedJMSServer.java
new file mode 100644
index 0000000..8e63326
--- /dev/null
+++ b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/SpawnedJMSServer.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.activemq.artemis.common;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
+import org.apache.activemq.artemis.core.server.ActiveMQServer;
+import org.apache.activemq.artemis.core.server.ActiveMQServers;
+import org.apache.activemq.artemis.jms.server.JMSServerManager;
+import org.apache.activemq.artemis.jms.server.impl.JMSServerManagerImpl;
+import org.apache.activemq.artemis.utils.FileUtil;
+
+public class SpawnedJMSServer {
+
+
+   public static ActiveMQServer server;
+   public static JMSServerManager serverManager;
+
+   // Using files may be useful for debugging (through print-data for instance)
+   private static final boolean useFiles = false;
+
+
+   public static void main(final String[] args) throws Exception {
+      try {
+         startServer();
+
+         System.out.println("Server started, ready to start client test");
+
+         // create the reader before printing OK so that if the test is quick
+         // we will still capture the STOP message sent by the client
+         InputStreamReader isr = new InputStreamReader(System.in);
+         BufferedReader br = new BufferedReader(isr);
+
+         System.out.println("OK");
+
+         String line = null;
+         while ((line = br.readLine()) != null) {
+            if ("STOP".equals(line.trim())) {
+               stopServer();
+               System.out.println("Server stopped");
+               System.exit(0);
+            }
+            else {
+               // stop anyway but with an error status
+               System.exit(1);
+            }
+         }
+      }
+      catch (Throwable t) {
+         t.printStackTrace();
+         String allStack = t.getCause().getMessage() + "|";
+         StackTraceElement[] stackTrace = t.getCause().getStackTrace();
+         for (StackTraceElement stackTraceElement : stackTrace) {
+            allStack += stackTraceElement.toString() + "|";
+         }
+         System.out.println(allStack);
+         System.out.println("KO");
+         System.exit(1);
+      }
+   }
+
+   public static ActiveMQServer startServer() throws Exception {
+      if (server == null) {
+         Configuration config = new ConfigurationImpl().addAcceptorConfiguration("netty", "tcp://localhost:61616").setSecurityEnabled(false).addConnectorConfiguration("netty", "tcp://localhost:61616");
+         File dataPlace = new File("./target/dataJoram");
+
+         FileUtil.deleteDirectory(dataPlace);
+
+         config.setJournalDirectory(new File(dataPlace, "./journal").getAbsolutePath()).
+            setPagingDirectory(new File(dataPlace, "./paging").getAbsolutePath()).
+            setLargeMessagesDirectory(new File(dataPlace, "./largemessages").getAbsolutePath()).
+            setBindingsDirectory(new File(dataPlace, "./bindings").getAbsolutePath()).setPersistenceEnabled(true);
+
+         // disable server persistence since JORAM tests do not restart server
+         server = ActiveMQServers.newActiveMQServer(config, useFiles);
+
+         serverManager = new JMSServerManagerImpl(server);
+         serverManager.start();
+      }
+      return server;
+   }
+
+   public static void stopServer() throws Exception {
+      if (server != null) {
+         serverManager.stop();
+      }
+      server = null;
+      serverManager = null;
+   }
+
+   // Constructors --------------------------------------------------
+
+   // Public --------------------------------------------------------
+
+   // Package protected ---------------------------------------------
+
+   // Protected -----------------------------------------------------
+
+   // Private -------------------------------------------------------
+
+   // Inner classes -------------------------------------------------
+
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContext.java
----------------------------------------------------------------------
diff --git a/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContext.java b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContext.java
new file mode 100644
index 0000000..9daecd8
--- /dev/null
+++ b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContext.java
@@ -0,0 +1,482 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.common.testjndi;
+
+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;
+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 org.apache.activemq.artemis.core.client.ActiveMQClientLogger;
+import org.apache.activemq.artemis.jndi.NameParserImpl;
+
+/**
+ * A read-only Context
+ * <p>
+ * This version assumes it and all its subcontext 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 optimise the performance of lookup.
+ * <p>
+ * <p>
+ * This implementation is intended to optimise 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 TestContext 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 TestContext() {
+      environment = new Hashtable<>();
+      bindings = new HashMap<>();
+      treeBindings = new HashMap<>();
+   }
+
+   public TestContext(Hashtable env) {
+      if (env == null) {
+         this.environment = new Hashtable<>();
+      }
+      else {
+         this.environment = new Hashtable<>(env);
+      }
+      this.bindings = Collections.EMPTY_MAP;
+      this.treeBindings = Collections.EMPTY_MAP;
+   }
+
+   public TestContext(Hashtable environment, Map<String, Object> bindings) {
+      if (environment == null) {
+         this.environment = new Hashtable<>();
+      }
+      else {
+         this.environment = new Hashtable<>(environment);
+      }
+      this.bindings = new HashMap<>();
+      treeBindings = new HashMap<>();
+      if (bindings != null) {
+         for (Map.Entry<String, Object> binding : bindings.entrySet()) {
+            try {
+               internalBind(binding.getKey(), binding.getValue());
+            }
+            catch (Throwable e) {
+               ActiveMQClientLogger.LOGGER.error("Failed to bind " + binding.getKey() + "=" + binding.getValue(), e);
+            }
+         }
+      }
+      frozen = true;
+   }
+
+   public TestContext(Hashtable environment, Map<String, Object> bindings, String nameInNamespace) {
+      this(environment, bindings);
+      this.nameInNamespace = nameInNamespace;
+   }
+
+   protected TestContext(TestContext clone, Hashtable env) {
+      this.bindings = clone.bindings;
+      this.treeBindings = clone.treeBindings;
+      this.environment = new Hashtable<>(env);
+   }
+
+   protected TestContext(TestContext 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 superclasses. 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 NamingException
+    */
+   protected Map<String, Object> internalBind(String name, Object value) throws NamingException {
+      assert name != null && name.length() > 0;
+
+      Map<String, Object> newBindings = new HashMap<>();
+      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 TestContext)) {
+            throw new NamingException("Something already bound where a subcontext should go");
+         }
+         TestContext readOnlyContext = (TestContext) o;
+         String remainder = name.substring(pos + 1);
+         Map<String, Object> subBindings = readOnlyContext.internalBind(remainder, value);
+         for (Map.Entry<String, Object> entry : subBindings.entrySet()) {
+            String subName = segment + "/" + entry.getKey();
+            Object bound = entry.getValue();
+            treeBindings.put(subName, bound);
+            newBindings.put(subName, bound);
+         }
+      }
+      return newBindings;
+   }
+
+   protected TestContext newContext() {
+      return new TestContext();
+   }
+
+   @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 TestContext) {
+         String prefix = getNameInNamespace();
+         if (prefix.length() > 0) {
+            prefix = prefix + SEPARATOR;
+         }
+         result = new TestContext((TestContext) 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<NameClassPair> 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<Binding> 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<NameClassPair> list(Name name) throws NamingException {
+      return list(name.toString());
+   }
+
+   @Override
+   public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
+      return listBindings(name.toString());
+   }
+
+   @Override
+   public void bind(Name name, Object obj) throws NamingException {
+      internalBind(name.toString(), obj);
+   }
+
+   @Override
+   public void bind(String name, Object obj) throws NamingException {
+      internalBind(name, obj);
+   }
+
+   @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 {
+      treeBindings.remove(name.toString());
+   }
+
+   @Override
+   public void unbind(String name) throws NamingException {
+      treeBindings.remove(name);
+   }
+
+   private abstract class LocalNamingEnumeration implements NamingEnumeration {
+
+      private final Iterator<Map.Entry<String, Object>> i = bindings.entrySet().iterator();
+
+      @Override
+      public boolean hasMore() throws NamingException {
+         return i.hasNext();
+      }
+
+      @Override
+      public boolean hasMoreElements() {
+         return i.hasNext();
+      }
+
+      protected Map.Entry<String, Object> getNext() {
+         return 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<String, Object> entry = getNext();
+         return new NameClassPair(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<String, Object> entry = getNext();
+         return new Binding(entry.getKey(), entry.getValue());
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/10dfe97e/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContextFactory.java
----------------------------------------------------------------------
diff --git a/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContextFactory.java b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContextFactory.java
new file mode 100644
index 0000000..3083fd3
--- /dev/null
+++ b/tests/joram-tests/src/test/java/org/apache/activemq/artemis/common/testjndi/TestContextFactory.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.common.testjndi;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
+import org.apache.activemq.artemis.jndi.LazyCreateContext;
+import org.apache.activemq.artemis.uri.ConnectionFactoryParser;
+
+/**
+ * A factory of the ActiveMQ Artemis InitialContext which contains
+ * {@link 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.
+ */
+public class TestContextFactory implements InitialContextFactory {
+
+   public static final String REFRESH_TIMEOUT = "refreshTimeout";
+   public static final String DISCOVERY_INITIAL_WAIT_TIMEOUT = "discoveryInitialWaitTimeout";
+   public static final String DYNAMIC_QUEUE_CONTEXT = "dynamicQueues";
+   public static final String DYNAMIC_TOPIC_CONTEXT = "dynamicTopics";
+   private String connectionFactoryPrefix = "connectionFactory.";
+   private String queuePrefix = "queue.";
+   private String topicPrefix = "topic.";
+
+   @Override
+   public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+      // lets create a factory
+      Map<String, Object> data = new ConcurrentHashMap<>();
+      for (Map.Entry<?, ?> entry : environment.entrySet()) {
+         String key = entry.getKey().toString();
+         if (key.startsWith(connectionFactoryPrefix)) {
+            String jndiName = key.substring(connectionFactoryPrefix.length());
+            try {
+               ConnectionFactory factory = createConnectionFactory((String) environment.get(key), jndiName);
+               data.put(jndiName, factory);
+            }
+            catch (Exception e) {
+               e.printStackTrace();
+               throw new NamingException("Invalid broker URL");
+            }
+         }
+      }
+
+      createQueues(data, environment);
+      createTopics(data, environment);
+
+      data.put(DYNAMIC_QUEUE_CONTEXT, new LazyCreateContext() {
+         private static final long serialVersionUID = 6503881346214855588L;
+
+         @Override
+         protected Object createEntry(String name) {
+            return ActiveMQJMSClient.createQueue(name);
+         }
+      });
+      data.put(DYNAMIC_TOPIC_CONTEXT, new LazyCreateContext() {
+         private static final long serialVersionUID = 2019166796234979615L;
+
+         @Override
+         protected Object createEntry(String name) {
+            return ActiveMQJMSClient.createTopic(name);
+         }
+      });
+
+      return createContext(environment, data);
+   }
+
+   // Properties
+   // -------------------------------------------------------------------------
+   public String getTopicPrefix() {
+      return topicPrefix;
+   }
+
+   public void setTopicPrefix(String topicPrefix) {
+      this.topicPrefix = topicPrefix;
+   }
+
+   public String getQueuePrefix() {
+      return queuePrefix;
+   }
+
+   public void setQueuePrefix(String queuePrefix) {
+      this.queuePrefix = queuePrefix;
+   }
+
+   // Implementation methods
+   // -------------------------------------------------------------------------
+
+   protected Context createContext(Hashtable<?, ?> environment, Map<String, Object> data) {
+      return new TestContext(environment, data);
+   }
+
+   protected void createQueues(Map<String, Object> data, Hashtable<?, ?> environment) {
+      for (Map.Entry<?, ?> entry : environment.entrySet()) {
+         String key = entry.getKey().toString();
+         if (key.startsWith(queuePrefix)) {
+            String jndiName = key.substring(queuePrefix.length());
+            data.put(jndiName, createQueue(entry.getValue().toString()));
+         }
+      }
+   }
+
+   protected void createTopics(Map<String, Object> data, Hashtable<?, ?> environment) {
+      for (Map.Entry<?, ?> entry : environment.entrySet()) {
+         String key = entry.getKey().toString();
+         if (key.startsWith(topicPrefix)) {
+            String jndiName = key.substring(topicPrefix.length());
+            data.put(jndiName, createTopic(entry.getValue().toString()));
+         }
+      }
+   }
+
+   /**
+    * Factory method to create new Queue instances
+    */
+   protected Queue createQueue(String name) {
+      return ActiveMQJMSClient.createQueue(name);
+   }
+
+   /**
+    * Factory method to create new Topic instances
+    */
+   protected Topic createTopic(String name) {
+      return ActiveMQJMSClient.createTopic(name);
+   }
+
+   /**
+    * Factory method to create a new connection factory from the given environment
+    */
+   protected ConnectionFactory createConnectionFactory(String uri, String name) throws Exception {
+      ConnectionFactoryParser parser = new ConnectionFactoryParser();
+      return parser.newObject(parser.expandURI(uri), name);
+   }
+}