You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by jb...@apache.org on 2022/12/17 07:45:47 UTC

[activemq-artemis] branch main updated: ARTEMIS-2876 Add JUnit5 Extensions for testing

This is an automated email from the ASF dual-hosted git repository.

jbertram pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new 76b8acc1dc ARTEMIS-2876 Add JUnit5 Extensions for testing
     new 24f0d4e3e8 This closes #4181
76b8acc1dc is described below

commit 76b8acc1dc3b9956d6ac8f5442f366c4b220dac2
Author: eidottermihi <ei...@gmail.com>
AuthorDate: Thu Aug 18 09:05:06 2022 +0200

    ARTEMIS-2876 Add JUnit5 Extensions for testing
    
    Adds a new module 'artemis-junit-5' which adds JUnit 5 Extensions for
    unit testing. For backwards compability, 'artemis-junit' still uses
    JUnit 4. Common stuff has been moved to 'artemis-junit-commons'. Work is
    based on the initial PR
    https://github.com/apache/activemq-artemis/pull/3436 by @luisalves00
---
 artemis-junit/{ => artemis-junit-4}/pom.xml        |  11 +-
 .../artemis/junit/ActiveMQConsumerResource.java    | 139 +++++++
 .../junit/ActiveMQDynamicProducerResource.java     | 217 +++++++++++
 .../artemis/junit/ActiveMQProducerResource.java    | 205 ++++++++++
 .../artemis/junit/EmbeddedActiveMQResource.java    | 364 ++++++++++++++++++
 .../artemis/junit/EmbeddedJMSResource.java         | 333 +++++++++++++++++
 .../junit/ActiveMQConsumerResourceTest.java        |   0
 .../junit/ActiveMQDynamicProducerResourceTest.java |   0
 ...roducerResourceWithoutAddressExceptionTest.java |   0
 ...QDynamicProducerResourceWithoutAddressTest.java |   0
 .../junit/ActiveMQProducerResourceTest.java        |   0
 ...dedActiveMQResourceCustomConfigurationTest.java |   0
 ...eddedActiveMQResourceFileConfigurationTest.java |   0
 .../junit/EmbeddedActiveMQResourceTest.java        |   0
 ...edJMSResourceMultipleFileConfigurationTest.java |   0
 .../junit/EmbeddedJMSResourceQueueTest.java        |   0
 ...ddedJMSResourceSingleFileConfigurationTest.java |   0
 .../junit/EmbeddedJMSResourceTopicTest.java        |   0
 .../MultipleEmbeddedActiveMQResourcesTest.java     |   0
 .../junit/MultipleEmbeddedJMSResourcesTest.java    |   0
 .../apache/activemq/artemis/junit/PlainTest.java   |   0
 .../test/resources/embedded-artemis-jms-only.xml   |   0
 .../test/resources/embedded-artemis-jms-server.xml |   0
 .../resources/embedded-artemis-minimal-server.xml  |   0
 .../src/test/resources/embedded-artemis-server.xml |   0
 .../src/test/resources/log4j2.properties           |  27 ++
 artemis-junit/{ => artemis-junit-5}/pom.xml        |  38 +-
 .../artemis/junit/ActiveMQConsumerExtension.java   | 137 +++++++
 .../junit/ActiveMQDynamicProducerExtension.java    | 215 +++++++++++
 .../artemis/junit/ActiveMQProducerExtension.java   | 201 ++++++++++
 .../artemis/junit/EmbeddedActiveMQExtension.java   | 362 ++++++++++++++++++
 .../junit/ActiveMQConsumerResourceTest.java        |  43 +--
 .../junit/ActiveMQDynamicProducerResourceTest.java |  46 +--
 ...roducerResourceWithoutAddressExceptionTest.java |  65 ++--
 ...QDynamicProducerResourceWithoutAddressTest.java |  52 +--
 .../junit/ActiveMQProducerResourceTest.java        |  42 ++-
 ...dedActiveMQResourceCustomConfigurationTest.java |  40 +-
 ...eddedActiveMQResourceFileConfigurationTest.java |  32 +-
 .../junit/EmbeddedActiveMQResourceTest.java        |  42 +--
 .../MultipleEmbeddedActiveMQResourcesTest.java     |  35 +-
 .../test/resources/embedded-artemis-jms-only.xml   |   0
 .../test/resources/embedded-artemis-jms-server.xml |   0
 .../resources/embedded-artemis-minimal-server.xml  |   0
 .../src/test/resources/embedded-artemis-server.xml |   0
 .../src/test/resources/log4j2.properties           |  27 ++
 artemis-junit/{ => artemis-junit-commons}/pom.xml  |  35 +-
 .../junit/AbstractActiveMQClientDelegate.java}     |  44 +--
 .../artemis/junit/ActiveMQConsumerDelegate.java}   |  71 ++--
 .../artemis/junit/ActiveMQConsumerOperations.java  |  45 +++
 .../junit/ActiveMQDynamicProducerDelegate.java}    | 110 ++----
 .../junit/ActiveMQDynamicProducerOperations.java   |  80 ++++
 .../artemis/junit/ActiveMQProducerDelegate.java}   | 165 ++-------
 .../artemis/junit/ActiveMQProducerOperations.java  | 135 +++++++
 .../artemis/junit/EmbeddedActiveMQDelegate.java}   | 411 ++++++---------------
 .../artemis/junit/EmbeddedActiveMQOperations.java  | 348 +++++++++++++++++
 .../artemis/junit/EmbeddedJMSDelegate.java}        | 276 +++++++-------
 .../artemis/junit/EmbeddedJMSOperations.java       | 177 +++++++++
 artemis-junit/pom.xml                              |  81 +---
 docs/user-manual/en/unit-testing.md                | 102 +++--
 pom.xml                                            |  29 +-
 60 files changed, 3713 insertions(+), 1069 deletions(-)

diff --git a/artemis-junit/pom.xml b/artemis-junit/artemis-junit-4/pom.xml
similarity index 91%
copy from artemis-junit/pom.xml
copy to artemis-junit/artemis-junit-4/pom.xml
index 8eda779568..efefe644db 100644
--- a/artemis-junit/pom.xml
+++ b/artemis-junit/artemis-junit-4/pom.xml
@@ -20,16 +20,16 @@
 
    <parent>
       <groupId>org.apache.activemq</groupId>
-      <artifactId>artemis-pom</artifactId>
+      <artifactId>artemis-junit-parent</artifactId>
       <version>2.28.0-SNAPSHOT</version>
    </parent>
 
    <artifactId>artemis-junit</artifactId>
    <packaging>jar</packaging>
-   <name>ActiveMQ Artemis JUnit Rules</name>
+   <name>ActiveMQ Artemis JUnit 4 Rules</name>
 
    <properties>
-      <activemq.basedir>${project.basedir}/..</activemq.basedir>
+      <activemq.basedir>${project.basedir}/../..</activemq.basedir>
    </properties>
 
    <dependencies>
@@ -38,6 +38,11 @@
          <artifactId>junit</artifactId>
          <scope>provided</scope>
       </dependency>
+      <dependency>
+         <groupId>org.apache.activemq</groupId>
+         <artifactId>artemis-junit-commons</artifactId>
+         <version>${project.version}</version>
+      </dependency>
       <!-- logging -->
       <dependency>
          <groupId>org.slf4j</groupId>
diff --git a/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
new file mode 100644
index 0000000000..5a02681648
--- /dev/null
+++ b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.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.activemq.artemis.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.junit.rules.ExternalResource;
+
+/**
+ * A JUnit Rule that embeds an ActiveMQ Artemis ClientConsumer into a test. This JUnit Rule is
+ * designed to simplify using ActiveMQ Artemis clients in unit tests. Adding the rule to a test will
+ * startup a ClientConsumer, which can then be used to consume messages from an ActiveMQ Artemis
+ * server.
+ *
+ * <pre>
+ * <code>
+ * public class SimpleTest {
+ *     &#64;Rule
+ *     public ActiveMQConsumerResource client = new ActiveMQProducerResource( "vm://0", "test.queue" );
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded client here
+ *         ClientMessage message = client.receiveMessage();
+ *     }
+ * }
+ * </code>
+ * </pre>
+ */
+public class ActiveMQConsumerResource extends ExternalResource implements ActiveMQConsumerOperations {
+
+   private final ActiveMQConsumerDelegate activeMQConsumer;
+
+   public ActiveMQConsumerResource(String url, String queueName) {
+      this.activeMQConsumer = new ActiveMQConsumerDelegate(url, queueName);
+   }
+
+   public ActiveMQConsumerResource(String url, String queueName, String username, String password) {
+      this.activeMQConsumer =
+               new ActiveMQConsumerDelegate(url, SimpleString.toSimpleString(queueName), username, password);
+   }
+
+   public ActiveMQConsumerResource(String url, SimpleString queueName, String username, String password) {
+      this.activeMQConsumer = new ActiveMQConsumerDelegate(url, queueName, username, password);
+   }
+
+   public ActiveMQConsumerResource(String url, SimpleString queueName) {
+      this.activeMQConsumer = new ActiveMQConsumerDelegate(url, queueName, null, null);
+   }
+
+   public ActiveMQConsumerResource(ServerLocator serverLocator, String queueName, String username, String password) {
+      this(serverLocator, SimpleString.toSimpleString(queueName), username, password);
+   }
+
+   public ActiveMQConsumerResource(ServerLocator serverLocator, String queueName) {
+      this(serverLocator, SimpleString.toSimpleString(queueName), null, null);
+   }
+
+   public ActiveMQConsumerResource(ServerLocator serverLocator, SimpleString queueName, String username,
+                                   String password) {
+      this.activeMQConsumer = new ActiveMQConsumerDelegate(serverLocator, queueName, username, password);
+   }
+
+   public ActiveMQConsumerResource(ServerLocator serverLocator, SimpleString queueName) {
+      this(serverLocator, queueName, null, null);
+   }
+
+   protected void createClient() {
+      activeMQConsumer.createClient();
+   }
+
+   protected void stopClient() {
+      activeMQConsumer.stopClient();
+   }
+
+   @Override
+   public boolean isAutoCreateQueue() {
+      return activeMQConsumer.isAutoCreateQueue();
+   }
+
+   @Override
+   public void setAutoCreateQueue(boolean autoCreateQueue) {
+      activeMQConsumer.setAutoCreateQueue(autoCreateQueue);
+   }
+
+   @Override
+   public ClientMessage receiveMessage() {
+      return activeMQConsumer.receiveMessage();
+   }
+
+   @Override
+   public ClientMessage receiveMessage(long timeout) {
+      return activeMQConsumer.receiveMessage(timeout);
+   }
+
+   @Override
+   protected void before() throws Throwable {
+      super.before();
+      activeMQConsumer.start();
+   }
+
+   @Override
+   protected void after() {
+      activeMQConsumer.stop();
+      super.after();
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      AbstractActiveMQClientDelegate.addMessageProperties(message, properties);
+   }
+
+   @Override
+   public long getDefaultReceiveTimeout() {
+      return activeMQConsumer.getDefaultReceiveTimeout();
+   }
+
+   @Override
+   public void setDefaultReceiveTimeout(long defaultReceiveTimeout) {
+      activeMQConsumer.setDefaultReceiveTimeout(defaultReceiveTimeout);
+   }
+
+}
diff --git a/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResource.java b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResource.java
new file mode 100644
index 0000000000..42338930b9
--- /dev/null
+++ b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResource.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.junit.rules.ExternalResource;
+
+/**
+ * A JUnit Rule that embeds an dynamic (i.e. unbound) ActiveMQ Artemis ClientProducer into a test.
+ * This JUnit Rule is designed to simplify using ActiveMQ Artemis clients in unit tests. Adding the
+ * rule to a test will startup an unbound ClientProducer, which can then be used to feed messages to
+ * any address on the ActiveMQ Artemis server.
+ *
+ * <pre>
+ * <code>
+ * public class SimpleTest {
+ *     &#64;Rule
+ *     public ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource( "vm://0");
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded ClientProducer here
+ *         producer.sendMessage( "test.address", "String Body" );
+ *     }
+ * }
+ * </code>
+ * </pre>
+ */
+public class ActiveMQDynamicProducerResource extends ExternalResource
+         implements ActiveMQDynamicProducerOperations, ActiveMQProducerOperations {
+
+   private final ActiveMQDynamicProducerDelegate activeMQDynamicProducer;
+
+   public ActiveMQDynamicProducerResource(String url, String username, String password) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url, username, password);
+   }
+
+   public ActiveMQDynamicProducerResource(String url) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url);
+   }
+
+   public ActiveMQDynamicProducerResource(ServerLocator serverLocator, String username, String password) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator, username, password);
+   }
+
+   public ActiveMQDynamicProducerResource(ServerLocator serverLocator) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator);
+   }
+
+   public ActiveMQDynamicProducerResource(String url, SimpleString address, String username, String password) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url, address, username, password);
+   }
+
+   public ActiveMQDynamicProducerResource(String url, SimpleString address) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url, address);
+   }
+
+   public ActiveMQDynamicProducerResource(ServerLocator serverLocator, SimpleString address, String username,
+                                          String password) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator, address, username, password);
+   }
+
+   public ActiveMQDynamicProducerResource(ServerLocator serverLocator, SimpleString address) {
+      activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator, address);
+   }
+
+   protected void createClient() {
+      activeMQDynamicProducer.createClient();
+   }
+
+   @Override
+   public boolean isUseDurableMessage() {
+      return activeMQDynamicProducer.isUseDurableMessage();
+   }
+
+   @Override
+   public void setUseDurableMessage(boolean useDurableMessage) {
+      activeMQDynamicProducer.setUseDurableMessage(useDurableMessage);
+   }
+
+   public void stopClient() {
+      activeMQDynamicProducer.stopClient();
+   }
+
+   @Override
+   public ClientMessage createMessage() {
+      return activeMQDynamicProducer.createMessage();
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body) {
+      return activeMQDynamicProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body) {
+      return activeMQDynamicProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(Map<String, Object> properties) {
+      return activeMQDynamicProducer.createMessage(properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public void sendMessage(ClientMessage message) {
+      activeMQDynamicProducer.sendMessage(message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body) {
+      return activeMQDynamicProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body) {
+      return activeMQDynamicProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(body, properties);
+   }
+
+   @Override
+   public void sendMessage(SimpleString targetAddress, ClientMessage message) {
+      activeMQDynamicProducer.sendMessage(targetAddress, message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, byte[] body) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, String body) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, byte[] body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, String body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body, properties);
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      AbstractActiveMQClientDelegate.addMessageProperties(message, properties);
+   }
+
+   public boolean isAutoCreateQueue() {
+      return activeMQDynamicProducer.isAutoCreateQueue();
+   }
+
+   public void setAutoCreateQueue(boolean autoCreateQueue) {
+      activeMQDynamicProducer.setAutoCreateQueue(autoCreateQueue);
+   }
+
+   @Override
+   protected void before() throws Throwable {
+      super.before();
+      activeMQDynamicProducer.start();
+   }
+
+   @Override
+   protected void after() {
+      activeMQDynamicProducer.stop();
+      super.after();
+   }
+
+}
diff --git a/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java
new file mode 100644
index 0000000000..5959c82dc0
--- /dev/null
+++ b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.junit.rules.ExternalResource;
+
+/**
+ * A JUnit Rule that embeds an ActiveMQ Artemis ClientProducer bound to a specific address into a
+ * test.
+ * <p>
+ * This JUnit Rule is designed to simplify using ActiveMQ Artemis clients in unit tests. Adding the
+ * rule to a test will startup a ClientProducer, which can then be used to feed messages to the
+ * bound address on an ActiveMQ Artemis server.
+ *
+ * <pre>
+ * <code>
+ * public class SimpleTest {
+ *     &#64;Rule
+ *     public ActiveMQProducerResource producer = new ActiveMQProducerResource( "vm://0", "test.queue");
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded ClientProducer here
+ *         producer.sendMessage( "String Body" );
+ *     }
+ * }
+ * </code>
+ * </pre>
+ */
+public class ActiveMQProducerResource extends ExternalResource implements ActiveMQProducerOperations {
+
+   private ActiveMQProducerDelegate activeMQProducer;
+
+   public ActiveMQProducerResource(String url, String username, String password) {
+      activeMQProducer = new ActiveMQProducerDelegate(url, username, password);
+   }
+
+   public ActiveMQProducerResource(String url) {
+      activeMQProducer = new ActiveMQProducerDelegate(url);
+   }
+
+   public ActiveMQProducerResource(ServerLocator serverLocator, String username, String password) {
+      activeMQProducer = new ActiveMQProducerDelegate(serverLocator, username, password);
+   }
+
+   public ActiveMQProducerResource(ServerLocator serverLocator) {
+      activeMQProducer = new ActiveMQProducerDelegate(serverLocator);
+   }
+
+   public ActiveMQProducerResource(String url, String address, String username, String password) {
+      activeMQProducer = new ActiveMQProducerDelegate(url, SimpleString.toSimpleString(address), username, password);
+   }
+
+   public ActiveMQProducerResource(String url, String address) {
+      activeMQProducer = new ActiveMQProducerDelegate(url, address, null, null);
+   }
+
+   public ActiveMQProducerResource(String url, SimpleString address, String username, String password) {
+      activeMQProducer = new ActiveMQProducerDelegate(url, address, username, password);
+   }
+
+   public ActiveMQProducerResource(String url, SimpleString address) {
+      activeMQProducer = new ActiveMQProducerDelegate(url, address, null, null);
+   }
+
+   public ActiveMQProducerResource(ServerLocator serverLocator, String address, String username, String password) {
+      activeMQProducer =
+               new ActiveMQProducerDelegate(serverLocator, SimpleString.toSimpleString(address), username, password);
+   }
+
+   public ActiveMQProducerResource(ServerLocator serverLocator, String address) {
+      activeMQProducer = new ActiveMQProducerDelegate(serverLocator, SimpleString.toSimpleString(address));
+   }
+
+   public ActiveMQProducerResource(ServerLocator serverLocator, SimpleString address, String username,
+                                   String password) {
+      activeMQProducer = new ActiveMQProducerDelegate(serverLocator, address, username, password);
+   }
+
+   public ActiveMQProducerResource(ServerLocator serverLocator, SimpleString address) {
+      activeMQProducer = new ActiveMQProducerDelegate(serverLocator, address, null, null);
+   }
+
+   @Override
+   protected void before() throws Throwable {
+      super.before();
+      activeMQProducer.start();
+   }
+
+   @Override
+   protected void after() {
+      activeMQProducer.stop();
+      super.after();
+   }
+
+   @Override
+   public boolean isUseDurableMessage() {
+      return activeMQProducer.isUseDurableMessage();
+   }
+
+   @Override
+   public void setUseDurableMessage(boolean useDurableMessage) {
+      activeMQProducer.setUseDurableMessage(useDurableMessage);
+   }
+
+   protected void createClient() {
+      activeMQProducer.createClient();
+   }
+
+   protected void stopClient() {
+      activeMQProducer.stopClient();
+   }
+
+   @Override
+   public ClientMessage createMessage() {
+      return activeMQProducer.createMessage();
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body) {
+      return activeMQProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body) {
+      return activeMQProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(Map<String, Object> properties) {
+      return activeMQProducer.createMessage(properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body, Map<String, Object> properties) {
+      return activeMQProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public void sendMessage(ClientMessage message) {
+      activeMQProducer.sendMessage(message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body) {
+      return activeMQProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body) {
+      return activeMQProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(Map<String, Object> properties) {
+      return activeMQProducer.sendMessage(properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQProducer.sendMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body, Map<String, Object> properties) {
+      return activeMQProducer.sendMessage(body, properties);
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      AbstractActiveMQClientDelegate.addMessageProperties(message, properties);
+   }
+
+   public boolean isAutoCreateQueue() {
+      return activeMQProducer.isAutoCreateQueue();
+   }
+
+   public void setAutoCreateQueue(boolean autoCreateQueue) {
+      activeMQProducer.setAutoCreateQueue(autoCreateQueue);
+   }
+
+}
diff --git a/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java
new file mode 100644
index 0000000000..daac2f27c7
--- /dev/null
+++ b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java
@@ -0,0 +1,364 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.server.Queue;
+import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
+import org.junit.rules.ExternalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A JUnit Rule that embeds an ActiveMQ Artemis server into a test. This JUnit Rule is designed to
+ * simplify using embedded servers in unit tests. Adding the rule to a test will startup an embedded
+ * server, which can then be used by client applications.
+ *
+ * <pre>
+ * <code>
+ * public class SimpleTest {
+ *     &#64;Rule
+ *     public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded server here
+ *     }
+ * }
+ * </code>
+ * </pre>
+ */
+public class EmbeddedActiveMQResource extends ExternalResource implements EmbeddedActiveMQOperations {
+
+   private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+   private EmbeddedActiveMQOperations embeddedActiveMQDelegate;
+
+   /**
+    * Create a default EmbeddedActiveMQResource
+    */
+   public EmbeddedActiveMQResource() {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate();
+   }
+
+   /**
+    * Create a default EmbeddedActiveMQResource with the specified serverId
+    * @param serverId server id
+    */
+   public EmbeddedActiveMQResource(int serverId) {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate(serverId);
+   }
+
+   /**
+    * Creates an EmbeddedActiveMQResource using the specified configuration
+    * @param configuration ActiveMQServer configuration
+    */
+   public EmbeddedActiveMQResource(Configuration configuration) {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate(configuration);
+   }
+
+   /**
+    * Creates an EmbeddedActiveMQResource using the specified configuration file
+    * @param filename ActiveMQServer configuration file name
+    */
+   public EmbeddedActiveMQResource(String filename) {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate(filename);
+   }
+
+   /**
+    * @see EmbeddedActiveMQDelegate#addMessageProperties(ClientMessage, Map)
+    */
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      EmbeddedActiveMQDelegate.addMessageProperties(message, properties);
+   }
+
+   @Override
+   public void start() {
+      embeddedActiveMQDelegate.start();
+   }
+
+   @Override
+   public void stop() {
+      embeddedActiveMQDelegate.stop();
+   }
+
+   /**
+    * Invoked by JUnit to setup the resource - start the embedded ActiveMQ Artemis server
+    */
+   @Override
+   protected void before() throws Throwable {
+      logger.info("Starting {}: {}", this.getClass().getSimpleName(), embeddedActiveMQDelegate.getServerName());
+
+      embeddedActiveMQDelegate.start();
+
+      super.before();
+   }
+
+   /**
+    * Invoked by JUnit to tear down the resource - stops the embedded ActiveMQ Artemis server
+    */
+   @Override
+   protected void after() {
+      logger.info("Stopping {}: {}", this.getClass().getSimpleName(), embeddedActiveMQDelegate.getServerName());
+
+      embeddedActiveMQDelegate.stop();
+
+      super.after();
+   }
+
+   @Override
+   public boolean isUseDurableMessage() {
+      return embeddedActiveMQDelegate.isUseDurableMessage();
+   }
+
+   @Override
+   public void setUseDurableMessage(boolean useDurableMessage) {
+      embeddedActiveMQDelegate.setUseDurableMessage(useDurableMessage);
+   }
+
+   @Override
+   public boolean isUseDurableQueue() {
+      return embeddedActiveMQDelegate.isUseDurableQueue();
+   }
+
+   @Override
+   public void setUseDurableQueue(boolean useDurableQueue) {
+      embeddedActiveMQDelegate.setUseDurableQueue(useDurableQueue);
+   }
+
+   @Override
+   public long getDefaultReceiveTimeout() {
+      return embeddedActiveMQDelegate.getDefaultReceiveTimeout();
+   }
+
+   @Override
+   public void setDefaultReceiveTimeout(long defaultReceiveTimeout) {
+      embeddedActiveMQDelegate.setDefaultReceiveTimeout(defaultReceiveTimeout);
+   }
+
+   @Override
+   public EmbeddedActiveMQ getServer() {
+      return embeddedActiveMQDelegate.getServer();
+   }
+
+   @Override
+   public String getServerName() {
+      return embeddedActiveMQDelegate.getServerName();
+   }
+
+   @Override
+   public String getVmURL() {
+      return embeddedActiveMQDelegate.getVmURL();
+   }
+
+   @Override
+   public long getMessageCount(String queueName) {
+      return embeddedActiveMQDelegate.getMessageCount(queueName);
+   }
+
+   @Override
+   public long getMessageCount(SimpleString queueName) {
+      return embeddedActiveMQDelegate.getMessageCount(queueName);
+   }
+
+   @Override
+   public Queue locateQueue(String queueName) {
+      return embeddedActiveMQDelegate.locateQueue(queueName);
+   }
+
+   @Override
+   public Queue locateQueue(SimpleString queueName) {
+      return embeddedActiveMQDelegate.locateQueue(queueName);
+   }
+
+   @Override
+   public List<Queue> getBoundQueues(String address) {
+      return embeddedActiveMQDelegate.getBoundQueues(address);
+   }
+
+   @Override
+   public List<Queue> getBoundQueues(SimpleString address) {
+      return embeddedActiveMQDelegate.getBoundQueues(address);
+   }
+
+   @Override
+   public Queue createQueue(String name) {
+      return embeddedActiveMQDelegate.createQueue(name);
+   }
+
+   @Override
+   public Queue createQueue(String address, String name) {
+      return embeddedActiveMQDelegate.createQueue(address, name);
+   }
+
+   @Override
+   public Queue createQueue(SimpleString address, SimpleString name) {
+      return embeddedActiveMQDelegate.createQueue(address, name);
+   }
+
+   @Override
+   public void createSharedQueue(String name, String user) {
+      embeddedActiveMQDelegate.createSharedQueue(name, user);
+   }
+
+   @Override
+   public void createSharedQueue(String address, String name, String user) {
+      embeddedActiveMQDelegate.createSharedQueue(address, name, user);
+   }
+
+   @Override
+   public void createSharedQueue(SimpleString address, SimpleString name, SimpleString user) {
+      embeddedActiveMQDelegate.createSharedQueue(address, name, user);
+   }
+
+   @Override
+   public ClientMessage createMessage() {
+      return embeddedActiveMQDelegate.createMessage();
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body) {
+      return embeddedActiveMQDelegate.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body) {
+      return embeddedActiveMQDelegate.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessageWithProperties(Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.createMessageWithProperties(properties);
+   }
+
+   @Override
+   public ClientMessage createMessageWithProperties(byte[] body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.createMessageWithProperties(body, properties);
+   }
+
+   @Override
+   public ClientMessage createMessageWithProperties(String body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.createMessageWithProperties(body, properties);
+   }
+
+   @Override
+   public void sendMessage(String address, ClientMessage message) {
+      embeddedActiveMQDelegate.sendMessage(address, message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String address, byte[] body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String address, String body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(String address, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(String address, byte[] body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(String address, String body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public void sendMessage(SimpleString address, ClientMessage message) {
+      embeddedActiveMQDelegate.sendMessage(address, message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString address, byte[] body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString address, String body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(SimpleString address, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(SimpleString address, byte[] body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(SimpleString address, String body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(String queueName) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(String queueName, long timeout) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName, timeout);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(SimpleString queueName) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(SimpleString queueName, long timeout) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName, timeout);
+   }
+
+   @Override
+   public ClientMessage browseMessage(String queueName) {
+      return embeddedActiveMQDelegate.browseMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage browseMessage(String queueName, long timeout) {
+      return embeddedActiveMQDelegate.browseMessage(queueName, timeout);
+   }
+
+   @Override
+   public ClientMessage browseMessage(SimpleString queueName) {
+      return embeddedActiveMQDelegate.browseMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage browseMessage(SimpleString queueName, long timeout) {
+      return embeddedActiveMQDelegate.browseMessage(queueName, timeout);
+   }
+
+}
diff --git a/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSResource.java b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSResource.java
new file mode 100644
index 0000000000..46a9b4f970
--- /dev/null
+++ b/artemis-junit/artemis-junit-4/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSResource.java
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import javax.jms.BytesMessage;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.server.Queue;
+import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
+import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
+import org.junit.rules.ExternalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Deprecated in favor of EmbeddedActiveMQResource. Since Artemis 2.0 all JMS specific broker
+ * management classes, interfaces, and methods have been deprecated in favor of their more general
+ * counter-parts. A JUnit Rule that embeds an ActiveMQ Artemis JMS server into a test. This JUnit
+ * Rule is designed to simplify using embedded servers in unit tests. Adding the rule to a test will
+ * startup an embedded JMS server, which can then be used by client applications.
+ *
+ * <pre>
+ * <code>
+ * public class SimpleTest {
+ *     &#64;Rule
+ *     public EmbeddedJMSResource server = new EmbeddedJMSResource();
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded server here
+ *     }
+ * }
+ * </code>
+ * </pre>
+ */
+@Deprecated
+public class EmbeddedJMSResource extends ExternalResource implements EmbeddedJMSOperations<EmbeddedJMSResource> {
+
+   private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+   private EmbeddedJMSDelegate embeddedJMSDelegate;
+
+   /**
+    * Create a default EmbeddedJMSResource
+    */
+   public EmbeddedJMSResource() {
+      this.embeddedJMSDelegate = new EmbeddedJMSDelegate();
+   }
+
+   /**
+    * Create a default EmbeddedJMSResource
+    */
+   public EmbeddedJMSResource(boolean useNetty) {
+      this.embeddedJMSDelegate = new EmbeddedJMSDelegate(useNetty);
+   }
+
+   /**
+    * Create a default EmbeddedJMSResource with the specified server id
+    */
+   public EmbeddedJMSResource(int serverId) {
+      this.embeddedJMSDelegate = new EmbeddedJMSDelegate(serverId);
+   }
+
+   /**
+    * Create an EmbeddedJMSResource with the specified configurations
+    * @param configuration ActiveMQServer configuration
+    * @param jmsConfiguration JMSServerManager configuration
+    */
+   public EmbeddedJMSResource(Configuration configuration, JMSConfiguration jmsConfiguration) {
+      this.embeddedJMSDelegate = new EmbeddedJMSDelegate(configuration, jmsConfiguration);
+   }
+
+   /**
+    * Create an EmbeddedJMSResource with the specified configuration file
+    * @param filename configuration file name
+    */
+   public EmbeddedJMSResource(String filename) {
+      this.embeddedJMSDelegate = new EmbeddedJMSDelegate(filename);
+   }
+
+   /**
+    * Create an EmbeddedJMSResource with the specified configuration file
+    * @param serverConfigurationFileName ActiveMQServer configuration file name
+    * @param jmsConfigurationFileName JMSServerManager configuration file name
+    */
+   public EmbeddedJMSResource(String serverConfigurationFileName, String jmsConfigurationFileName) {
+      this.embeddedJMSDelegate = new EmbeddedJMSDelegate(serverConfigurationFileName, jmsConfigurationFileName);
+   }
+
+   @Override
+   public EmbeddedJMSResource addAcceptor(String name, String uri) throws Exception {
+      this.embeddedJMSDelegate.addAcceptor(name, uri);
+      return this;
+   }
+
+   public static void setMessageProperties(Message message, Map<String, Object> properties) {
+      EmbeddedJMSDelegate.setMessageProperties(message, properties);
+   }
+
+   @Override
+   public void start() {
+      embeddedJMSDelegate.start();
+   }
+
+   @Override
+   public void stop() {
+      embeddedJMSDelegate.stop();
+   }
+
+   /**
+    * Start the embedded ActiveMQ Broker
+    * <p>
+    * Invoked by JUnit to setup the resource
+    */
+   @Override
+   protected void before() throws Throwable {
+      logger.info("Starting {}: {}", this.getClass().getSimpleName(), embeddedJMSDelegate.getServerName());
+
+      embeddedJMSDelegate.start();
+
+      super.before();
+   }
+
+   /**
+    * Stop the embedded ActiveMQ Broker
+    * <p>
+    * Invoked by JUnit to tear down the resource
+    */
+   @Override
+   protected void after() {
+      logger.info("Stopping {}: {}", this.getClass().getSimpleName(), embeddedJMSDelegate.getServerName());
+
+      super.after();
+
+      embeddedJMSDelegate.stop();
+   }
+
+   @Override
+   public EmbeddedJMS getJmsServer() {
+      return embeddedJMSDelegate.getJmsServer();
+   }
+
+   @Override
+   public String getServerName() {
+      return embeddedJMSDelegate.getServerName();
+   }
+
+   @Override
+   public String getVmURL() {
+      return embeddedJMSDelegate.getVmURL();
+   }
+
+   @Override
+   public Queue getDestinationQueue(String destinationName) {
+      return embeddedJMSDelegate.getDestinationQueue(destinationName);
+   }
+
+   @Override
+   public List<Queue> getTopicQueues(String topicName) {
+      return embeddedJMSDelegate.getTopicQueues(topicName);
+   }
+
+   @Override
+   public long getMessageCount(String destinationName) {
+      return embeddedJMSDelegate.getMessageCount(destinationName);
+   }
+
+   @Override
+   public BytesMessage createBytesMessage() {
+      return embeddedJMSDelegate.createBytesMessage();
+   }
+
+   @Override
+   public TextMessage createTextMessage() {
+      return embeddedJMSDelegate.createTextMessage();
+   }
+
+   @Override
+   public MapMessage createMapMessage() {
+      return embeddedJMSDelegate.createMapMessage();
+   }
+
+   @Override
+   public ObjectMessage createObjectMessage() {
+      return embeddedJMSDelegate.createObjectMessage();
+   }
+
+   @Override
+   public StreamMessage createStreamMessage() {
+      return embeddedJMSDelegate.createStreamMessage();
+   }
+
+   @Override
+   public BytesMessage createMessage(byte[] body) {
+      return embeddedJMSDelegate.createMessage(body);
+   }
+
+   @Override
+   public TextMessage createMessage(String body) {
+      return embeddedJMSDelegate.createMessage(body);
+   }
+
+   @Override
+   public MapMessage createMessage(Map<String, Object> body) {
+      return embeddedJMSDelegate.createMessage(body);
+   }
+
+   @Override
+   public ObjectMessage createMessage(Serializable body) {
+      return embeddedJMSDelegate.createMessage(body);
+   }
+
+   @Override
+   public BytesMessage createMessage(byte[] body, Map<String, Object> properties) {
+      return embeddedJMSDelegate.createMessage(body, properties);
+   }
+
+   @Override
+   public TextMessage createMessage(String body, Map<String, Object> properties) {
+      return embeddedJMSDelegate.createMessage(body, properties);
+   }
+
+   @Override
+   public MapMessage createMessage(Map<String, Object> body, Map<String, Object> properties) {
+      return embeddedJMSDelegate.createMessage(body, properties);
+   }
+
+   @Override
+   public ObjectMessage createMessage(Serializable body, Map<String, Object> properties) {
+      return embeddedJMSDelegate.createMessage(body, properties);
+   }
+
+   @Override
+   public void pushMessage(String destinationName, Message message) {
+      embeddedJMSDelegate.pushMessage(destinationName, message);
+   }
+
+   @Override
+   public BytesMessage pushMessage(String destinationName, byte[] body) {
+      return embeddedJMSDelegate.pushMessage(destinationName, body);
+   }
+
+   @Override
+   public TextMessage pushMessage(String destinationName, String body) {
+      return embeddedJMSDelegate.pushMessage(destinationName, body);
+   }
+
+   @Override
+   public MapMessage pushMessage(String destinationName, Map<String, Object> body) {
+      return embeddedJMSDelegate.pushMessage(destinationName, body);
+   }
+
+   @Override
+   public ObjectMessage pushMessage(String destinationName, Serializable body) {
+      return embeddedJMSDelegate.pushMessage(destinationName, body);
+   }
+
+   @Override
+   public BytesMessage pushMessageWithProperties(String destinationName, byte[] body, Map<String, Object> properties) {
+      return embeddedJMSDelegate.pushMessageWithProperties(destinationName, body, properties);
+   }
+
+   @Override
+   public TextMessage pushMessageWithProperties(String destinationName, String body, Map<String, Object> properties) {
+      return embeddedJMSDelegate.pushMessageWithProperties(destinationName, body, properties);
+   }
+
+   @Override
+   public MapMessage pushMessageWithProperties(String destinationName, Map<String, Object> body,
+                                               Map<String, Object> properties) {
+      return embeddedJMSDelegate.pushMessageWithProperties(destinationName, body, properties);
+   }
+
+   @Override
+   public ObjectMessage pushMessageWithProperties(String destinationName, Serializable body,
+                                                  Map<String, Object> properties) {
+      return embeddedJMSDelegate.pushMessageWithProperties(destinationName, body, properties);
+   }
+
+   @Override
+   public Message peekMessage(String destinationName) {
+      return embeddedJMSDelegate.peekMessage(destinationName);
+   }
+
+   @Override
+   public BytesMessage peekBytesMessage(String destinationName) {
+      return embeddedJMSDelegate.peekBytesMessage(destinationName);
+   }
+
+   @Override
+   public TextMessage peekTextMessage(String destinationName) {
+      return embeddedJMSDelegate.peekTextMessage(destinationName);
+   }
+
+   @Override
+   public MapMessage peekMapMessage(String destinationName) {
+      return embeddedJMSDelegate.peekMapMessage(destinationName);
+   }
+
+   @Override
+   public ObjectMessage peekObjectMessage(String destinationName) {
+      return embeddedJMSDelegate.peekObjectMessage(destinationName);
+   }
+
+   @Override
+   public StreamMessage peekStreamMessage(String destinationName) {
+      return embeddedJMSDelegate.peekStreamMessage(destinationName);
+   }
+
+}
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
similarity index 100%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
rename to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceMultipleFileConfigurationTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
similarity index 100%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
rename to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceQueueTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
similarity index 100%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
rename to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceSingleFileConfigurationTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
similarity index 100%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
rename to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/EmbeddedJMSResourceTopicTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
similarity index 100%
copy from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
copy to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
similarity index 100%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
rename to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedJMSResourcesTest.java
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/PlainTest.java b/artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/PlainTest.java
similarity index 100%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/PlainTest.java
rename to artemis-junit/artemis-junit-4/src/test/java/org/apache/activemq/artemis/junit/PlainTest.java
diff --git a/artemis-junit/src/test/resources/embedded-artemis-jms-only.xml b/artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-jms-only.xml
similarity index 100%
copy from artemis-junit/src/test/resources/embedded-artemis-jms-only.xml
copy to artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-jms-only.xml
diff --git a/artemis-junit/src/test/resources/embedded-artemis-jms-server.xml b/artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-jms-server.xml
similarity index 100%
copy from artemis-junit/src/test/resources/embedded-artemis-jms-server.xml
copy to artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-jms-server.xml
diff --git a/artemis-junit/src/test/resources/embedded-artemis-minimal-server.xml b/artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-minimal-server.xml
similarity index 100%
copy from artemis-junit/src/test/resources/embedded-artemis-minimal-server.xml
copy to artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-minimal-server.xml
diff --git a/artemis-junit/src/test/resources/embedded-artemis-server.xml b/artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-server.xml
similarity index 100%
copy from artemis-junit/src/test/resources/embedded-artemis-server.xml
copy to artemis-junit/artemis-junit-4/src/test/resources/embedded-artemis-server.xml
diff --git a/artemis-junit/artemis-junit-4/src/test/resources/log4j2.properties b/artemis-junit/artemis-junit-4/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..bb6a22f054
--- /dev/null
+++ b/artemis-junit/artemis-junit-4/src/test/resources/log4j2.properties
@@ -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.
+
+# Log4J 2 configuration
+
+rootLogger = INFO, console
+
+logger.activemq.name=org.apache.activemq
+logger.activemq.level=INFO
+
+# Console appender
+appender.console.type=Console
+appender.console.name=console
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=%d %-5level [%logger] %msg%n
diff --git a/artemis-junit/pom.xml b/artemis-junit/artemis-junit-5/pom.xml
similarity index 83%
copy from artemis-junit/pom.xml
copy to artemis-junit/artemis-junit-5/pom.xml
index 8eda779568..0ef14f29ca 100644
--- a/artemis-junit/pom.xml
+++ b/artemis-junit/artemis-junit-5/pom.xml
@@ -20,24 +20,31 @@
 
    <parent>
       <groupId>org.apache.activemq</groupId>
-      <artifactId>artemis-pom</artifactId>
+      <artifactId>artemis-junit-parent</artifactId>
       <version>2.28.0-SNAPSHOT</version>
    </parent>
 
-   <artifactId>artemis-junit</artifactId>
+   <artifactId>artemis-junit-5</artifactId>
    <packaging>jar</packaging>
-   <name>ActiveMQ Artemis JUnit Rules</name>
+   <name>ActiveMQ Artemis JUnit 5 Extensions</name>
 
    <properties>
-      <activemq.basedir>${project.basedir}/..</activemq.basedir>
+      <activemq.basedir>${project.basedir}/../..</activemq.basedir>
    </properties>
 
    <dependencies>
       <dependency>
-         <groupId>junit</groupId>
-         <artifactId>junit</artifactId>
-         <scope>provided</scope>
+         <groupId>org.junit.jupiter</groupId>
+         <artifactId>junit-jupiter-api</artifactId>
+         <scope>compile</scope>
       </dependency>
+
+      <dependency>
+         <groupId>org.junit.jupiter</groupId>
+         <artifactId>junit-jupiter-engine</artifactId>
+         <scope>runtime</scope>
+      </dependency>
+
       <!-- logging -->
       <dependency>
          <groupId>org.slf4j</groupId>
@@ -65,20 +72,15 @@
       </dependency>
       <dependency>
          <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-core-client</artifactId>
+         <artifactId>artemis-commons</artifactId>
          <version>${project.version}</version>
       </dependency>
       <dependency>
          <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-commons</artifactId>
+         <artifactId>artemis-junit-commons</artifactId>
          <version>${project.version}</version>
       </dependency>
 
-      <dependency>
-         <groupId>jakarta.jms</groupId>
-         <artifactId>jakarta.jms-api</artifactId>
-      </dependency>
-
       <dependency>
          <groupId>org.apache.activemq</groupId>
          <artifactId>artemis-unit-test-support</artifactId>
@@ -86,11 +88,11 @@
          <scope>test</scope>
       </dependency>
 
+      <dependency>
+         <groupId>jakarta.jms</groupId>
+         <artifactId>jakarta.jms-api</artifactId>
+      </dependency>
 
-      <!-- The johnzon-core and json-api contents are repackaged in -commons,
-     However maven can still need them during tests, which run against
-     the original -commons classes when built+run in the same reactor,
-     and not the jar containing the shaded bits. -->
       <dependency>
          <groupId>org.apache.johnzon</groupId>
          <artifactId>johnzon-core</artifactId>
diff --git a/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerExtension.java b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerExtension.java
new file mode 100644
index 0000000000..7362412360
--- /dev/null
+++ b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerExtension.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+/**
+ * A JUnit Extension that embeds an ActiveMQ Artemis ClientConsumer into a test.
+ * <p>
+ * This JUnit Extension is designed to simplify using ActiveMQ Artemis clients in unit tests.  Adding the extension to a test will startup
+ * a ClientConsumer, which can then be used to consume messages from an ActiveMQ Artemis server.
+ *
+ * <pre><code>
+ * public class SimpleTest {
+ *     &#64;RegisterExtension
+ *     private ActiveMQConsumerExtension client = new ActiveMQConsumerExtension( "vm://0", "test.queue" );
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded client here
+ *         ClientMessage message = client.receiveMessage();
+ *     }
+ * }
+ * </code></pre>
+ */
+public class ActiveMQConsumerExtension implements BeforeAllCallback, AfterAllCallback, ActiveMQConsumerOperations {
+
+   private final ActiveMQConsumerDelegate activeMQConsumerDelegate;
+
+   public ActiveMQConsumerExtension(String url, String queueName) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(url, queueName);
+   }
+
+   public ActiveMQConsumerExtension(String url, String queueName, String username, String password) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(url, queueName, username, password);
+   }
+
+   public ActiveMQConsumerExtension(String url, SimpleString queueName, String username, String password) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(url, queueName, username, password);
+   }
+
+   public ActiveMQConsumerExtension(String url, SimpleString queueName) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(url, queueName);
+   }
+
+   public ActiveMQConsumerExtension(ServerLocator serverLocator, String queueName, String username, String password) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(serverLocator, queueName, username, password);
+   }
+
+   public ActiveMQConsumerExtension(ServerLocator serverLocator, String queueName) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(serverLocator, queueName);
+   }
+
+   public ActiveMQConsumerExtension(ServerLocator serverLocator,
+                                    SimpleString queueName,
+                                    String username,
+                                    String password) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(serverLocator, queueName, username, password);
+   }
+
+   public ActiveMQConsumerExtension(ServerLocator serverLocator, SimpleString queueName) {
+      this.activeMQConsumerDelegate = new ActiveMQConsumerDelegate(serverLocator, queueName);
+   }
+
+   @Override
+   public void beforeAll(ExtensionContext context) throws Exception {
+      activeMQConsumerDelegate.start();
+   }
+
+   @Override
+   public void afterAll(ExtensionContext context) throws Exception {
+      activeMQConsumerDelegate.stop();
+   }
+
+   @Override
+   public long getDefaultReceiveTimeout() {
+      return activeMQConsumerDelegate.getDefaultReceiveTimeout();
+   }
+
+   @Override
+   public void setDefaultReceiveTimeout(long defaultReceiveTimeout) {
+      activeMQConsumerDelegate.setDefaultReceiveTimeout(defaultReceiveTimeout);
+   }
+
+   protected void createClient() {
+      activeMQConsumerDelegate.createClient();
+   }
+
+   protected void stopClient() {
+      activeMQConsumerDelegate.stopClient();
+   }
+
+   @Override
+   public boolean isAutoCreateQueue() {
+      return activeMQConsumerDelegate.isAutoCreateQueue();
+   }
+
+   @Override
+   public void setAutoCreateQueue(boolean autoCreateQueue) {
+      activeMQConsumerDelegate.setAutoCreateQueue(autoCreateQueue);
+   }
+
+   @Override
+   public ClientMessage receiveMessage() {
+      return activeMQConsumerDelegate.receiveMessage();
+   }
+
+   @Override
+   public ClientMessage receiveMessage(long timeout) {
+      return activeMQConsumerDelegate.receiveMessage(timeout);
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      AbstractActiveMQClientDelegate.addMessageProperties(message, properties);
+   }
+}
diff --git a/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerExtension.java b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerExtension.java
new file mode 100644
index 0000000000..b02e199a8b
--- /dev/null
+++ b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerExtension.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+/**
+ * A JUnit Extension that embeds an dynamic (i.e. unbound) ActiveMQ Artemis ClientProducer into a test.
+ * <p>
+ * This JUnit Extension is designed to simplify using ActiveMQ Artemis clients in unit tests.  Adding the extension to a test will startup
+ * an unbound ClientProducer, which can then be used to feed messages to any address on the ActiveMQ Artemis server.
+ *
+ * <pre><code>
+ * public class SimpleTest {
+ *     &#64;RegisterExtension
+ *     private ActiveMQDynamicProducerExtension producer = new ActiveMQDynamicProducerExtension("vm://0");
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded ClientProducer here
+ *         producer.sendMessage( "test.address", "String Body" );
+ *     }
+ * }
+ * </code></pre>
+ */
+public class ActiveMQDynamicProducerExtension implements BeforeAllCallback, AfterAllCallback, ActiveMQDynamicProducerOperations, ActiveMQProducerOperations {
+
+   private ActiveMQDynamicProducerDelegate activeMQDynamicProducer;
+
+   public ActiveMQDynamicProducerExtension(String url, String username, String password) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url, username, password);
+   }
+
+   public ActiveMQDynamicProducerExtension(String url) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url);
+   }
+
+   public ActiveMQDynamicProducerExtension(ServerLocator serverLocator, String username, String password) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator, username, password);
+   }
+
+   public ActiveMQDynamicProducerExtension(ServerLocator serverLocator) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator);
+   }
+
+   public ActiveMQDynamicProducerExtension(String url, SimpleString address, String username, String password) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url, address, username, password);
+   }
+
+   public ActiveMQDynamicProducerExtension(String url, SimpleString address) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(url, address);
+   }
+
+   public ActiveMQDynamicProducerExtension(ServerLocator serverLocator,
+                                           SimpleString address,
+                                           String username,
+                                           String password) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator, address, username, password);
+   }
+
+   public ActiveMQDynamicProducerExtension(ServerLocator serverLocator, SimpleString address) {
+      this.activeMQDynamicProducer = new ActiveMQDynamicProducerDelegate(serverLocator, address);
+   }
+
+   protected void createClient() {
+      activeMQDynamicProducer.createClient();
+   }
+
+   @Override
+   public boolean isUseDurableMessage() {
+      return activeMQDynamicProducer.isUseDurableMessage();
+   }
+
+   @Override
+   public void setUseDurableMessage(boolean useDurableMessage) {
+      activeMQDynamicProducer.setUseDurableMessage(useDurableMessage);
+   }
+
+   public void stopClient() {
+      activeMQDynamicProducer.stopClient();
+   }
+
+   @Override
+   public ClientMessage createMessage() {
+      return activeMQDynamicProducer.createMessage();
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body) {
+      return activeMQDynamicProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body) {
+      return activeMQDynamicProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(Map<String, Object> properties) {
+      return activeMQDynamicProducer.createMessage(properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public void sendMessage(ClientMessage message) {
+      activeMQDynamicProducer.sendMessage(message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body) {
+      return activeMQDynamicProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body) {
+      return activeMQDynamicProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(body, properties);
+   }
+
+   @Override
+   public void sendMessage(SimpleString targetAddress, ClientMessage message) {
+      activeMQDynamicProducer.sendMessage(targetAddress, message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, byte[] body) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, String body) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, byte[] body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString targetAddress, String body, Map<String, Object> properties) {
+      return activeMQDynamicProducer.sendMessage(targetAddress, body, properties);
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      AbstractActiveMQClientDelegate.addMessageProperties(message, properties);
+   }
+
+   public boolean isAutoCreateQueue() {
+      return activeMQDynamicProducer.isAutoCreateQueue();
+   }
+
+   public void setAutoCreateQueue(boolean autoCreateQueue) {
+      activeMQDynamicProducer.setAutoCreateQueue(autoCreateQueue);
+   }
+
+   @Override
+   public void beforeAll(ExtensionContext context) throws Exception {
+      activeMQDynamicProducer.start();
+   }
+
+   @Override
+   public void afterAll(ExtensionContext context) throws Exception {
+      activeMQDynamicProducer.stop();
+   }
+}
diff --git a/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerExtension.java b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerExtension.java
new file mode 100644
index 0000000000..22b8655a81
--- /dev/null
+++ b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerExtension.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.api.core.client.ServerLocator;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+
+/**
+ * A JUnit Extension that embeds an ActiveMQ Artemis ClientProducer bound to a specific address into a test.
+ * <p>
+ * This JUnit Extension is designed to simplify using ActiveMQ Artemis clients in unit tests. Adding the extension to a test will startup
+ * a ClientProducer, which can then be used to feed messages to the bound address on an ActiveMQ Artemis server.
+ *
+ * <pre><code>
+ * public class SimpleTest {
+ *     &#64;RegisterExtension
+ *     private ActiveMQProducerExtension producer = new ActiveMQProducerExtension( "vm://0", "test.queue");
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded ClientProducer here
+ *         producer.sendMessage( "String Body" );
+ *     }
+ * }
+ * </code></pre>
+ */
+public class ActiveMQProducerExtension implements BeforeAllCallback, AfterAllCallback, ActiveMQProducerOperations {
+
+   private ActiveMQProducerDelegate activeMQProducer;
+
+   protected ActiveMQProducerExtension(String url, String username, String password) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(url, username, password);
+   }
+
+   protected ActiveMQProducerExtension(String url) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(url);
+   }
+
+   protected ActiveMQProducerExtension(ServerLocator serverLocator, String username, String password) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(serverLocator, username, password);
+   }
+
+   protected ActiveMQProducerExtension(ServerLocator serverLocator) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(serverLocator);
+   }
+
+   public ActiveMQProducerExtension(String url, String address, String username, String password) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(url, address, username, password);
+   }
+
+   public ActiveMQProducerExtension(String url, String address) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(url, address);
+   }
+
+   public ActiveMQProducerExtension(String url, SimpleString address, String username, String password) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(url, address, username, password);
+   }
+
+   public ActiveMQProducerExtension(String url, SimpleString address) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(url, address);
+   }
+
+   public ActiveMQProducerExtension(ServerLocator serverLocator, String address, String username, String password) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(serverLocator, address, username, password);
+   }
+
+   public ActiveMQProducerExtension(ServerLocator serverLocator, String address) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(serverLocator, address);
+   }
+
+   public ActiveMQProducerExtension(ServerLocator serverLocator,
+                                    SimpleString address,
+                                    String username,
+                                    String password) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(serverLocator, address, username, password);
+   }
+
+   public ActiveMQProducerExtension(ServerLocator serverLocator, SimpleString address) {
+      this.activeMQProducer = new ActiveMQProducerDelegate(serverLocator, address);
+   }
+
+   @Override
+   public void beforeAll(ExtensionContext context) throws Exception {
+      activeMQProducer.start();
+   }
+
+   @Override
+   public void afterAll(ExtensionContext context) throws Exception {
+      activeMQProducer.stop();
+   }
+
+   @Override
+   public boolean isUseDurableMessage() {
+      return activeMQProducer.isUseDurableMessage();
+   }
+
+   @Override
+   public void setUseDurableMessage(boolean useDurableMessage) {
+      activeMQProducer.setUseDurableMessage(useDurableMessage);
+   }
+
+   protected void createClient() {
+      activeMQProducer.createClient();
+   }
+
+   protected void stopClient() {
+      activeMQProducer.stopClient();
+   }
+
+   @Override
+   public ClientMessage createMessage() {
+      return activeMQProducer.createMessage();
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body) {
+      return activeMQProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body) {
+      return activeMQProducer.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(Map<String, Object> properties) {
+      return activeMQProducer.createMessage(properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body, Map<String, Object> properties) {
+      return activeMQProducer.createMessage(body, properties);
+   }
+
+   @Override
+   public void sendMessage(ClientMessage message) {
+      activeMQProducer.sendMessage(message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body) {
+      return activeMQProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body) {
+      return activeMQProducer.sendMessage(body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(Map<String, Object> properties) {
+      return activeMQProducer.sendMessage(properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(byte[] body, Map<String, Object> properties) {
+      return activeMQProducer.sendMessage(body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String body, Map<String, Object> properties) {
+      return activeMQProducer.sendMessage(body, properties);
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      AbstractActiveMQClientDelegate.addMessageProperties(message, properties);
+   }
+
+   public boolean isAutoCreateQueue() {
+      return activeMQProducer.isAutoCreateQueue();
+   }
+
+   public void setAutoCreateQueue(boolean autoCreateQueue) {
+      activeMQProducer.setAutoCreateQueue(autoCreateQueue);
+   }
+}
diff --git a/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQExtension.java b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQExtension.java
new file mode 100644
index 0000000000..e201ddc868
--- /dev/null
+++ b/artemis-junit/artemis-junit-5/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQExtension.java
@@ -0,0 +1,362 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.core.config.Configuration;
+import org.apache.activemq.artemis.core.server.Queue;
+import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A JUnit Extension that embeds an ActiveMQ Artemis server into a test.
+ * <p>
+ * This JUnit Extension is designed to simplify using embedded servers in unit tests. Adding the extension to a test will startup
+ * an embedded server, which can then be used by client applications.
+ *
+ * <pre><code>
+ * public class SimpleTest {
+ *     &#64;RegisterExtension
+ *     private EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
+ *
+ *     &#64;Test
+ *     public void testSomething() throws Exception {
+ *         // Use the embedded server here
+ *     }
+ * }
+ * </code></pre>
+ */
+public class EmbeddedActiveMQExtension implements BeforeAllCallback, AfterAllCallback, EmbeddedActiveMQOperations {
+
+   private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+   private EmbeddedActiveMQOperations embeddedActiveMQDelegate;
+
+   /**
+    * Create a default EmbeddedActiveMQExtension
+    */
+   public EmbeddedActiveMQExtension() {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate();
+   }
+
+   /**
+    * Create a default EmbeddedActiveMQExtension with the specified serverId
+    *
+    * @param serverId server id
+    */
+   public EmbeddedActiveMQExtension(int serverId) {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate(serverId);
+   }
+
+   /**
+    * Creates an EmbeddedActiveMQExtension using the specified configuration
+    *
+    * @param configuration ActiveMQServer configuration
+    */
+   public EmbeddedActiveMQExtension(Configuration configuration) {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate(configuration);
+   }
+
+   /**
+    * Creates an EmbeddedActiveMQExtension using the specified configuration file
+    *
+    * @param filename ActiveMQServer configuration file name
+    */
+   public EmbeddedActiveMQExtension(String filename) {
+      this.embeddedActiveMQDelegate = new EmbeddedActiveMQDelegate(filename);
+   }
+
+   @Override
+   public void start() {
+      embeddedActiveMQDelegate.start();
+   }
+
+   @Override
+   public void stop() {
+      embeddedActiveMQDelegate.stop();
+   }
+
+   /**
+    * Invoked by JUnit to setup the resource - start the embedded ActiveMQ Artemis server
+    */
+   @Override
+   public void beforeAll(ExtensionContext context) throws Exception {
+      logger.info("Starting {}: {}", this.getClass().getSimpleName(), embeddedActiveMQDelegate.getServerName());
+
+      embeddedActiveMQDelegate.start();
+
+   }
+
+   /**
+    * Invoked by JUnit to tear down the resource - stops the embedded ActiveMQ Artemis server
+    */
+   @Override
+   public void afterAll(ExtensionContext context) throws Exception {
+      logger.info("Stopping {}: {}", this.getClass().getSimpleName(), embeddedActiveMQDelegate.getServerName());
+
+      embeddedActiveMQDelegate.stop();
+
+   }
+
+   public static void addMessageProperties(ClientMessage message, Map<String, Object> properties) {
+      EmbeddedActiveMQDelegate.addMessageProperties(message, properties);
+   }
+
+   @Override
+   public boolean isUseDurableMessage() {
+      return embeddedActiveMQDelegate.isUseDurableMessage();
+   }
+
+   @Override
+   public void setUseDurableMessage(boolean useDurableMessage) {
+      embeddedActiveMQDelegate.setUseDurableMessage(useDurableMessage);
+   }
+
+   @Override
+   public boolean isUseDurableQueue() {
+      return embeddedActiveMQDelegate.isUseDurableQueue();
+   }
+
+   @Override
+   public void setUseDurableQueue(boolean useDurableQueue) {
+      embeddedActiveMQDelegate.setUseDurableQueue(useDurableQueue);
+   }
+
+   @Override
+   public long getDefaultReceiveTimeout() {
+      return embeddedActiveMQDelegate.getDefaultReceiveTimeout();
+   }
+
+   @Override
+   public void setDefaultReceiveTimeout(long defaultReceiveTimeout) {
+      embeddedActiveMQDelegate.setDefaultReceiveTimeout(defaultReceiveTimeout);
+   }
+
+   @Override
+   public EmbeddedActiveMQ getServer() {
+      return embeddedActiveMQDelegate.getServer();
+   }
+
+   @Override
+   public String getServerName() {
+      return embeddedActiveMQDelegate.getServerName();
+   }
+
+   @Override
+   public String getVmURL() {
+      return embeddedActiveMQDelegate.getVmURL();
+   }
+
+   @Override
+   public long getMessageCount(String queueName) {
+      return embeddedActiveMQDelegate.getMessageCount(queueName);
+   }
+
+   @Override
+   public long getMessageCount(SimpleString queueName) {
+      return embeddedActiveMQDelegate.getMessageCount(queueName);
+   }
+
+   @Override
+   public Queue locateQueue(String queueName) {
+      return embeddedActiveMQDelegate.locateQueue(queueName);
+   }
+
+   @Override
+   public Queue locateQueue(SimpleString queueName) {
+      return embeddedActiveMQDelegate.locateQueue(queueName);
+   }
+
+   @Override
+   public List<Queue> getBoundQueues(String address) {
+      return embeddedActiveMQDelegate.getBoundQueues(address);
+   }
+
+   @Override
+   public List<Queue> getBoundQueues(SimpleString address) {
+      return embeddedActiveMQDelegate.getBoundQueues(address);
+   }
+
+   @Override
+   public Queue createQueue(String name) {
+      return embeddedActiveMQDelegate.createQueue(name);
+   }
+
+   @Override
+   public Queue createQueue(String address, String name) {
+      return embeddedActiveMQDelegate.createQueue(address, name);
+   }
+
+   @Override
+   public Queue createQueue(SimpleString address, SimpleString name) {
+      return embeddedActiveMQDelegate.createQueue(address, name);
+   }
+
+   @Override
+   public void createSharedQueue(String name, String user) {
+      embeddedActiveMQDelegate.createSharedQueue(name, user);
+   }
+
+   @Override
+   public void createSharedQueue(String address, String name, String user) {
+      embeddedActiveMQDelegate.createSharedQueue(address, name, user);
+   }
+
+   @Override
+   public void createSharedQueue(SimpleString address, SimpleString name, SimpleString user) {
+      embeddedActiveMQDelegate.createSharedQueue(address, name, user);
+   }
+
+   @Override
+   public ClientMessage createMessage() {
+      return embeddedActiveMQDelegate.createMessage();
+   }
+
+   @Override
+   public ClientMessage createMessage(byte[] body) {
+      return embeddedActiveMQDelegate.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessage(String body) {
+      return embeddedActiveMQDelegate.createMessage(body);
+   }
+
+   @Override
+   public ClientMessage createMessageWithProperties(Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.createMessageWithProperties(properties);
+   }
+
+   @Override
+   public ClientMessage createMessageWithProperties(byte[] body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.createMessageWithProperties(body, properties);
+   }
+
+   @Override
+   public ClientMessage createMessageWithProperties(String body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.createMessageWithProperties(body, properties);
+   }
+
+   @Override
+   public void sendMessage(String address, ClientMessage message) {
+      embeddedActiveMQDelegate.sendMessage(address, message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String address, byte[] body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(String address, String body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(String address, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(String address, byte[] body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(String address, String body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public void sendMessage(SimpleString address, ClientMessage message) {
+      embeddedActiveMQDelegate.sendMessage(address, message);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString address, byte[] body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessage(SimpleString address, String body) {
+      return embeddedActiveMQDelegate.sendMessage(address, body);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(SimpleString address, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(SimpleString address, byte[] body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public ClientMessage sendMessageWithProperties(SimpleString address, String body, Map<String, Object> properties) {
+      return embeddedActiveMQDelegate.sendMessageWithProperties(address, body, properties);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(String queueName) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(String queueName, long timeout) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName, timeout);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(SimpleString queueName) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage receiveMessage(SimpleString queueName, long timeout) {
+      return embeddedActiveMQDelegate.receiveMessage(queueName, timeout);
+   }
+
+   @Override
+   public ClientMessage browseMessage(String queueName) {
+      return embeddedActiveMQDelegate.browseMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage browseMessage(String queueName, long timeout) {
+      return embeddedActiveMQDelegate.browseMessage(queueName, timeout);
+   }
+
+   @Override
+   public ClientMessage browseMessage(SimpleString queueName) {
+      return embeddedActiveMQDelegate.browseMessage(queueName);
+   }
+
+   @Override
+   public ClientMessage browseMessage(SimpleString queueName, long timeout) {
+      return embeddedActiveMQDelegate.browseMessage(queueName, timeout);
+   }
+}
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
similarity index 68%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
index eb0894b4b8..e0edfcd7a4 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResourceTest.java
@@ -21,13 +21,16 @@ import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class ActiveMQConsumerResourceTest {
 
    static final SimpleString TEST_QUEUE = new SimpleString("test.queue");
@@ -37,7 +40,6 @@ public class ActiveMQConsumerResourceTest {
 
    static final String ASSERT_SENT_FORMAT = "Message should have been sent to %s";
    static final String ASSERT_RECEIVED_FORMAT = "Message should have been received from %s";
-   static final String ASSERT_COUNT_FORMAT = "Unexpected message count in queue %s";
 
    static {
       TEST_PROPERTIES = new HashMap<String, Object>(2);
@@ -45,42 +47,41 @@ public class ActiveMQConsumerResourceTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
+   @RegisterExtension
+   @Order(1)
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
 
-   ActiveMQConsumerResource consumer = new ActiveMQConsumerResource(server.getVmURL(), TEST_QUEUE);
-
-   @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(consumer);
+   @RegisterExtension
+   @Order(2)
+   public ActiveMQConsumerExtension consumer = new ActiveMQConsumerExtension(server.getVmURL(), TEST_QUEUE);
 
    ClientMessage sent = null;
 
-   @After
-   public void tearDown() throws Exception {
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS), sent);
+   @AfterAll
+   public void tearDown() {
+      assertNotNull(sent, String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS));
 
       ClientMessage received = consumer.receiveMessage();
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_ADDRESS), received);
-
-      server.stop();
+      assertNotNull(received, String.format(ASSERT_RECEIVED_FORMAT, TEST_ADDRESS));
    }
 
    @Test
-   public void testSendBytes() throws Exception {
+   public void testSendBytes() {
       sent = server.sendMessage(TEST_ADDRESS, TEST_BODY.getBytes());
    }
 
    @Test
-   public void testSendString() throws Exception {
+   public void testSendString() {
       sent = server.sendMessage(TEST_ADDRESS, TEST_BODY);
    }
 
    @Test
-   public void testSendBytesAndProperties() throws Exception {
+   public void testSendBytesAndProperties() {
       sent = server.sendMessageWithProperties(TEST_ADDRESS, TEST_BODY.getBytes(), TEST_PROPERTIES);
    }
 
    @Test
-   public void testSendStringAndProperties() throws Exception {
+   public void testSendStringAndProperties() {
       sent = server.sendMessageWithProperties(TEST_ADDRESS, TEST_BODY, TEST_PROPERTIES);
    }
 
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
similarity index 69%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
index b58c4fa67a..7acb6bb359 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceTest.java
@@ -21,13 +21,16 @@ import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class ActiveMQDynamicProducerResourceTest {
 
    static final SimpleString TEST_QUEUE_ONE = new SimpleString("test.queue.one");
@@ -45,50 +48,49 @@ public class ActiveMQDynamicProducerResourceTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
+   @RegisterExtension
+   @Order(1)
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
 
-   ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL(), TEST_QUEUE_ONE);
-
-   @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   @RegisterExtension
+   @Order(2)
+   public ActiveMQDynamicProducerExtension producer = new ActiveMQDynamicProducerExtension(server.getVmURL(), TEST_QUEUE_ONE);
 
    ClientMessage sentOne = null;
    ClientMessage sentTwo = null;
 
-   @After
-   public void tearDown() throws Exception {
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE), sentOne);
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO), sentTwo);
+   @AfterAll
+   public void tearDown() {
+      assertNotNull(sentOne, String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE));
+      assertNotNull(sentTwo, String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO));
 
       ClientMessage receivedOne = server.receiveMessage(TEST_QUEUE_ONE);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_ONE), receivedOne);
+      assertNotNull(receivedOne, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_ONE));
 
       ClientMessage receivedTwo = server.receiveMessage(TEST_QUEUE_TWO);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO), receivedTwo);
-
-      server.stop();
+      assertNotNull(receivedTwo, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO));
    }
 
    @Test
-   public void testSendBytes() throws Exception {
+   public void testSendBytes() {
       sentOne = producer.sendMessage(TEST_BODY.getBytes());
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY.getBytes());
    }
 
    @Test
-   public void testSendString() throws Exception {
+   public void testSendString() {
       sentOne = producer.sendMessage(TEST_BODY);
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY);
    }
 
    @Test
-   public void testSendBytesAndProperties() throws Exception {
+   public void testSendBytesAndProperties() {
       sentOne = producer.sendMessage(TEST_BODY.getBytes(), TEST_PROPERTIES);
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY.getBytes(), TEST_PROPERTIES);
    }
 
    @Test
-   public void testSendStringAndProperties() throws Exception {
+   public void testSendStringAndProperties() {
       sentOne = producer.sendMessage(TEST_BODY, TEST_PROPERTIES);
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY, TEST_PROPERTIES);
    }
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
similarity index 54%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
index 037bed5483..f2ec2929ca 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressExceptionTest.java
@@ -21,12 +21,16 @@ import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
+
+@TestInstance(Lifecycle.PER_CLASS)
 public class ActiveMQDynamicProducerResourceWithoutAddressExceptionTest {
 
    static final SimpleString TEST_QUEUE_ONE = new SimpleString("test.queue.one");
@@ -39,43 +43,48 @@ public class ActiveMQDynamicProducerResourceWithoutAddressExceptionTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
-
-   ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
+   @RegisterExtension
+   @Order(1)
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
 
-   @After
-   public void tear() {
-      server.stop();
-   }
-
-   @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   @RegisterExtension
+   @Order(2)
+   public ActiveMQDynamicProducerExtension producer = new ActiveMQDynamicProducerExtension(server.getVmURL());
 
    ClientMessage sentOne = null;
 
-   @Before
+   @BeforeAll
    public void setUp() throws Exception {
       producer.setAutoCreateQueue(false);
       server.createQueue(TEST_QUEUE_ONE, TEST_QUEUE_ONE);
    }
 
-   @Test(expected = IllegalArgumentException.class)
-   public void testSendBytesToDefaultAddress() throws Exception {
-      sentOne = producer.sendMessage(TEST_BODY.getBytes());
+   @Test
+   public void testSendBytesToDefaultAddress() {
+      assertThrows(IllegalArgumentException.class, () -> {
+         sentOne = producer.sendMessage(TEST_BODY.getBytes());
+      });
    }
 
-   @Test(expected = IllegalArgumentException.class)
-   public void testSendStringToDefaultAddress() throws Exception {
-      sentOne = producer.sendMessage(TEST_BODY);
+   @Test
+   public void testSendStringToDefaultAddress() {
+      assertThrows(IllegalArgumentException.class, () -> {
+         sentOne = producer.sendMessage(TEST_BODY);
+      });
    }
 
-   @Test(expected = IllegalArgumentException.class)
-   public void testSendBytesAndPropertiesToDefaultAddress() throws Exception {
-      sentOne = producer.sendMessage(TEST_BODY.getBytes(), TEST_PROPERTIES);
+   @Test
+   public void testSendBytesAndPropertiesToDefaultAddress() {
+      assertThrows(IllegalArgumentException.class, () -> {
+         sentOne = producer.sendMessage(TEST_BODY.getBytes(), TEST_PROPERTIES);
+      });
+
    }
 
-   @Test(expected = IllegalArgumentException.class)
-   public void testSendStringAndPropertiesToDefaultAddress() throws Exception {
-      sentOne = producer.sendMessage(TEST_BODY, TEST_PROPERTIES);
+   @Test
+   public void testSendStringAndPropertiesToDefaultAddress() {
+      assertThrows(IllegalArgumentException.class, () -> {
+         sentOne = producer.sendMessage(TEST_BODY, TEST_PROPERTIES);
+      });
    }
 }
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
similarity index 69%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
index bc2fcef58e..93141d6c98 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResourceWithoutAddressTest.java
@@ -21,14 +21,17 @@ import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class ActiveMQDynamicProducerResourceWithoutAddressTest {
 
    static final SimpleString TEST_QUEUE_ONE = new SimpleString("test.queue.one");
@@ -46,57 +49,56 @@ public class ActiveMQDynamicProducerResourceWithoutAddressTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
+   @RegisterExtension
+   @Order(1)
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
 
-   ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
-
-   @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   @RegisterExtension
+   @Order(2)
+   public ActiveMQDynamicProducerExtension producer = new ActiveMQDynamicProducerExtension(server.getVmURL());
 
    ClientMessage sentOne = null;
    ClientMessage sentTwo = null;
 
-   @Before
-   public void setUp() throws Exception {
+   @BeforeAll
+   public void setUp() {
       producer.setAutoCreateQueue(false);
       server.createQueue(TEST_QUEUE_ONE, TEST_QUEUE_ONE);
       server.createQueue(TEST_QUEUE_TWO, TEST_QUEUE_TWO);
    }
 
-   @After
-   public void tearDown() throws Exception {
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE), sentOne);
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO), sentTwo);
+   @AfterAll
+   public void tearDown() {
+      assertNotNull(sentOne, String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE));
+      assertNotNull(sentTwo, String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO));
 
       ClientMessage receivedOne = server.receiveMessage(TEST_QUEUE_ONE);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_ONE), receivedOne);
+      assertNotNull(receivedOne, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_ONE));
 
       ClientMessage receivedTwo = server.receiveMessage(TEST_QUEUE_TWO);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO), receivedTwo);
-
-      server.stop();
+      assertNotNull(receivedTwo, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO));
    }
 
    @Test
-   public void testSendBytes() throws Exception {
+   public void testSendBytes() {
       sentOne = producer.sendMessage(TEST_QUEUE_ONE, TEST_BODY.getBytes());
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY.getBytes());
    }
 
    @Test
-   public void testSendString() throws Exception {
+   public void testSendString() {
       sentOne = producer.sendMessage(TEST_QUEUE_ONE, TEST_BODY);
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY);
    }
 
    @Test
-   public void testSendBytesAndProperties() throws Exception {
+   public void testSendBytesAndProperties() {
       sentOne = producer.sendMessage(TEST_QUEUE_ONE, TEST_BODY.getBytes(), TEST_PROPERTIES);
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY.getBytes(), TEST_PROPERTIES);
    }
 
    @Test
-   public void testSendStringAndProperties() throws Exception {
+   public void testSendStringAndProperties() {
       sentOne = producer.sendMessage(TEST_QUEUE_ONE, TEST_BODY, TEST_PROPERTIES);
       sentTwo = producer.sendMessage(TEST_QUEUE_TWO, TEST_BODY, TEST_PROPERTIES);
    }
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
similarity index 67%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
index 8d0394bfd7..eb51d0e40c 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/ActiveMQProducerResourceTest.java
@@ -21,13 +21,16 @@ import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class ActiveMQProducerResourceTest {
 
    static final SimpleString TEST_QUEUE = new SimpleString("test.queue");
@@ -37,7 +40,6 @@ public class ActiveMQProducerResourceTest {
 
    static final String ASSERT_SENT_FORMAT = "Message should have been sent to %s";
    static final String ASSERT_RECEIVED_FORMAT = "Message should have been received from %s";
-   static final String ASSERT_COUNT_FORMAT = "Unexpected message count in queue %s";
 
    static {
       TEST_PROPERTIES = new HashMap<String, Object>(2);
@@ -45,41 +47,41 @@ public class ActiveMQProducerResourceTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
-
-   ActiveMQProducerResource producer = new ActiveMQProducerResource(server.getVmURL(), TEST_ADDRESS);
-
-   @Rule
-   public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+   @RegisterExtension
+   @Order(1)
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
 
+   @RegisterExtension
+   @Order(2)
+   public ActiveMQDynamicProducerExtension producer = new ActiveMQDynamicProducerExtension(server.getVmURL(), TEST_ADDRESS);
 
    ClientMessage sent = null;
 
-   @After
-   public void checkResults() throws Exception {
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS), sent);
+   @AfterAll
+   public void checkResults() {
+      assertNotNull(sent, String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS));
 
       ClientMessage received = server.receiveMessage(TEST_QUEUE);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE), received);
+      assertNotNull(received, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE));
    }
 
    @Test
-   public void testSendBytes() throws Exception {
+   public void testSendBytes() {
       sent = producer.sendMessage(TEST_BODY.getBytes());
    }
 
    @Test
-   public void testSendString() throws Exception {
+   public void testSendString() {
       sent = producer.sendMessage(TEST_BODY);
    }
 
    @Test
-   public void testSendBytesAndProperties() throws Exception {
+   public void testSendBytesAndProperties() {
       sent = producer.sendMessage(TEST_BODY.getBytes(), TEST_PROPERTIES);
    }
 
    @Test
-   public void testSendStringAndProperties() throws Exception {
+   public void testSendStringAndProperties() {
       sent = producer.sendMessage(TEST_BODY, TEST_PROPERTIES);
    }
 
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
similarity index 61%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
index 0ee10be34e..8d8aabba7b 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceCustomConfigurationTest.java
@@ -22,16 +22,17 @@ import org.apache.activemq.artemis.api.core.QueueConfiguration;
 import org.apache.activemq.artemis.core.config.Configuration;
 import org.apache.activemq.artemis.core.config.impl.ConfigurationImpl;
 import org.apache.activemq.artemis.core.server.Queue;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-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 static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class EmbeddedActiveMQResourceCustomConfigurationTest {
 
    static final String TEST_QUEUE = "test.queue";
@@ -40,28 +41,21 @@ public class EmbeddedActiveMQResourceCustomConfigurationTest {
    QueueConfiguration queueConfiguration = new QueueConfiguration(TEST_QUEUE).setAddress(TEST_ADDRESS);
    Configuration customConfiguration = new ConfigurationImpl().setPersistenceEnabled(false).setSecurityEnabled(true).addQueueConfiguration(queueConfiguration);
 
-   private EmbeddedActiveMQResource server = new EmbeddedActiveMQResource(customConfiguration);
-
-   @Rule
-   public RuleChain rulechain = RuleChain.outerRule(server);
-
-   @After
-   public void tear() {
-      server.stop();
-   }
+   @RegisterExtension
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension(customConfiguration);
 
    @Test
-   public void testCustomConfiguration() throws Exception {
+   public void testCustomConfiguration() {
       Configuration configuration = server.getServer().getActiveMQServer().getConfiguration();
 
-      assertFalse("Persistence should have been disabled", configuration.isPersistenceEnabled());
-      assertTrue("Security should have been enabled", configuration.isSecurityEnabled());
+      assertFalse(configuration.isPersistenceEnabled(), "Persistence should have been disabled");
+      assertTrue(configuration.isSecurityEnabled(), "Security should have been enabled");
 
-      assertNotNull(TEST_QUEUE + " should exist", server.locateQueue(TEST_QUEUE));
+      assertNotNull(server.locateQueue(TEST_QUEUE), TEST_QUEUE + " should exist");
 
       List<Queue> boundQueues = server.getBoundQueues(TEST_ADDRESS);
-      assertNotNull("List should never be null", boundQueues);
-      assertEquals("Should have one queue bound to address " + TEST_ADDRESS, 1, boundQueues.size());
+      assertNotNull(boundQueues, "List should never be null");
+      assertEquals(1, boundQueues.size(), "Should have one queue bound to address " + TEST_ADDRESS);
    }
 
 }
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
similarity index 61%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
index 63bd4b67ec..018680df10 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceFileConfigurationTest.java
@@ -19,37 +19,31 @@ package org.apache.activemq.artemis.junit;
 import java.util.List;
 
 import org.apache.activemq.artemis.core.server.Queue;
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class EmbeddedActiveMQResourceFileConfigurationTest {
 
    // These values must match the contents of the configuration file
    static final String TEST_QUEUE = "test.queue";
    static final String TEST_ADDRESS = "test.address";
 
-   private EmbeddedActiveMQResource server = new EmbeddedActiveMQResource("embedded-artemis-server.xml");
-
-   @Rule
-   public RuleChain rulechain = RuleChain.outerRule(server);
-
-   @After
-   public void tear() {
-      server.stop();
-   }
+   @RegisterExtension
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension("embedded-artemis-server.xml");
 
    @Test
-   public void testConfiguredQueue() throws Exception {
-      assertNotNull(TEST_QUEUE + " should exist", server.locateQueue(TEST_QUEUE));
+   public void testConfiguredQueue() {
+      assertNotNull(server.locateQueue(TEST_QUEUE), TEST_QUEUE + " should exist");
 
       List<Queue> boundQueues = server.getBoundQueues(TEST_ADDRESS);
-      assertNotNull("List should never be null", boundQueues);
-      assertEquals("Should have one queue bound to address " + TEST_ADDRESS, 1, boundQueues.size());
+      assertNotNull(boundQueues, "List should never be null");
+      assertEquals(1, boundQueues.size(), "Should have one queue bound to address " + TEST_ADDRESS);
    }
 
 }
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
similarity index 72%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
index a41cfd0925..7a1f342e54 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResourceTest.java
@@ -21,14 +21,16 @@ import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class EmbeddedActiveMQResourceTest {
 
    static final SimpleString TEST_QUEUE = new SimpleString("test.queue");
@@ -46,45 +48,41 @@ public class EmbeddedActiveMQResourceTest {
       TEST_PROPERTIES.put("PropertyTwo", "Property Value 2");
    }
 
-   public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
-
-   @Rule
-   public RuleChain rulechain = RuleChain.outerRule(server);
+   @RegisterExtension
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
 
    ClientMessage sent = null;
 
-   @Before
-   public void setUp() throws Exception {
+   @BeforeAll
+   public void setUp() {
       server.createQueue(TEST_ADDRESS, TEST_QUEUE);
    }
 
-   @After
-   public void tearDown() throws Exception {
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS), sent);
+   @AfterAll
+   public void tearDown() {
+      assertNotNull(sent, String.format(ASSERT_SENT_FORMAT, TEST_ADDRESS));
 
       ClientMessage received = server.receiveMessage(TEST_QUEUE);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_ADDRESS), received);
-
-      server.stop();
+      assertNotNull(received, String.format(ASSERT_RECEIVED_FORMAT, TEST_ADDRESS));
    }
 
    @Test
-   public void testSendBytes() throws Exception {
+   public void testSendBytes() {
       sent = server.sendMessage(TEST_ADDRESS, TEST_BODY.getBytes());
    }
 
    @Test
-   public void testSendString() throws Exception {
+   public void testSendString() {
       sent = server.sendMessage(TEST_ADDRESS, TEST_BODY);
    }
 
    @Test
-   public void testSendBytesAndProperties() throws Exception {
+   public void testSendBytesAndProperties() {
       sent = server.sendMessageWithProperties(TEST_ADDRESS, TEST_BODY.getBytes(), TEST_PROPERTIES);
    }
 
    @Test
-   public void testSendStringAndProperties() throws Exception {
+   public void testSendStringAndProperties() {
       sent = server.sendMessageWithProperties(TEST_ADDRESS, TEST_BODY, TEST_PROPERTIES);
    }
 
diff --git a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
similarity index 73%
rename from artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
rename to artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
index 6712a0c9e7..29a6f3731a 100644
--- a/artemis-junit/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
+++ b/artemis-junit/artemis-junit-5/src/test/java/org/apache/activemq/artemis/junit/MultipleEmbeddedActiveMQResourcesTest.java
@@ -19,13 +19,16 @@ package org.apache.activemq.artemis.junit;
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.client.ClientMessage;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.RuleChain;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.TestInstance.Lifecycle;
 
+@TestInstance(Lifecycle.PER_CLASS)
 public class MultipleEmbeddedActiveMQResourcesTest {
 
    static final SimpleString TEST_QUEUE_ONE = new SimpleString("test.queue.one");
@@ -37,16 +40,16 @@ public class MultipleEmbeddedActiveMQResourcesTest {
 
    static final String ASSERT_SENT_FORMAT = "Message should have been sent to %s";
    static final String ASSERT_RECEIVED_FORMAT = "Message should have been received from %s";
-   static final String ASSERT_COUNT_FORMAT = "Unexpected message count in queue %s";
 
-   public EmbeddedActiveMQResource serverOne = new EmbeddedActiveMQResource(0);
+   @RegisterExtension
+   @Order(1)
+   public EmbeddedActiveMQExtension serverOne = new EmbeddedActiveMQExtension(1);
 
-   public EmbeddedActiveMQResource serverTwo = new EmbeddedActiveMQResource(1);
+   @RegisterExtension
+   @Order(2)
+   public EmbeddedActiveMQExtension serverTwo = new EmbeddedActiveMQExtension(2);
 
-   @Rule
-   public RuleChain rulechain = RuleChain.outerRule(serverOne).around(serverTwo);
-
-   @Before
+   @BeforeAll
    public void setUp() throws Exception {
       serverOne.getServer().getActiveMQServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setDeadLetterAddress(SimpleString.toSimpleString("DLA")).setExpiryAddress(SimpleString.toSimpleString("Expiry")));
       serverTwo.getServer().getActiveMQServer().getAddressSettingsRepository().addMatch("#", new AddressSettings().setDeadLetterAddress(SimpleString.toSimpleString("DLA")).setExpiryAddress(SimpleString.toSimpleString("Expiry")));
@@ -58,16 +61,16 @@ public class MultipleEmbeddedActiveMQResourcesTest {
    @Test
    public void testMultipleServers() throws Exception {
       ClientMessage sentOne = serverOne.sendMessage(TEST_ADDRESS_ONE, TEST_BODY);
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE), sentOne);
+      assertNotNull(sentOne, String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_ONE));
 
       ClientMessage receivedOne = serverOne.receiveMessage(TEST_QUEUE_ONE);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO), receivedOne);
+      assertNotNull(receivedOne, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO));
 
       ClientMessage sentTwo = serverTwo.sendMessage(TEST_ADDRESS_TWO, TEST_BODY);
-      assertNotNull(String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO), sentOne);
+      assertNotNull(sentOne, String.format(ASSERT_SENT_FORMAT, TEST_QUEUE_TWO));
 
       ClientMessage receivedTwo = serverTwo.receiveMessage(TEST_QUEUE_TWO);
-      assertNotNull(String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO), receivedOne);
+      assertNotNull(receivedOne, String.format(ASSERT_RECEIVED_FORMAT, TEST_QUEUE_TWO));
    }
 
 }
diff --git a/artemis-junit/src/test/resources/embedded-artemis-jms-only.xml b/artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-jms-only.xml
similarity index 100%
rename from artemis-junit/src/test/resources/embedded-artemis-jms-only.xml
rename to artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-jms-only.xml
diff --git a/artemis-junit/src/test/resources/embedded-artemis-jms-server.xml b/artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-jms-server.xml
similarity index 100%
rename from artemis-junit/src/test/resources/embedded-artemis-jms-server.xml
rename to artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-jms-server.xml
diff --git a/artemis-junit/src/test/resources/embedded-artemis-minimal-server.xml b/artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-minimal-server.xml
similarity index 100%
rename from artemis-junit/src/test/resources/embedded-artemis-minimal-server.xml
rename to artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-minimal-server.xml
diff --git a/artemis-junit/src/test/resources/embedded-artemis-server.xml b/artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-server.xml
similarity index 100%
rename from artemis-junit/src/test/resources/embedded-artemis-server.xml
rename to artemis-junit/artemis-junit-5/src/test/resources/embedded-artemis-server.xml
diff --git a/artemis-junit/artemis-junit-5/src/test/resources/log4j2.properties b/artemis-junit/artemis-junit-5/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..bb6a22f054
--- /dev/null
+++ b/artemis-junit/artemis-junit-5/src/test/resources/log4j2.properties
@@ -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.
+
+# Log4J 2 configuration
+
+rootLogger = INFO, console
+
+logger.activemq.name=org.apache.activemq
+logger.activemq.level=INFO
+
+# Console appender
+appender.console.type=Console
+appender.console.name=console
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=%d %-5level [%logger] %msg%n
diff --git a/artemis-junit/pom.xml b/artemis-junit/artemis-junit-commons/pom.xml
similarity index 70%
copy from artemis-junit/pom.xml
copy to artemis-junit/artemis-junit-commons/pom.xml
index 8eda779568..3aabb3769a 100644
--- a/artemis-junit/pom.xml
+++ b/artemis-junit/artemis-junit-commons/pom.xml
@@ -20,24 +20,19 @@
 
    <parent>
       <groupId>org.apache.activemq</groupId>
-      <artifactId>artemis-pom</artifactId>
+      <artifactId>artemis-junit-parent</artifactId>
       <version>2.28.0-SNAPSHOT</version>
    </parent>
 
-   <artifactId>artemis-junit</artifactId>
+   <artifactId>artemis-junit-commons</artifactId>
    <packaging>jar</packaging>
-   <name>ActiveMQ Artemis JUnit Rules</name>
+   <name>ActiveMQ Artemis JUnit Commons</name>
 
    <properties>
-      <activemq.basedir>${project.basedir}/..</activemq.basedir>
+      <activemq.basedir>${project.basedir}/../..</activemq.basedir>
    </properties>
 
    <dependencies>
-      <dependency>
-         <groupId>junit</groupId>
-         <artifactId>junit</artifactId>
-         <scope>provided</scope>
-      </dependency>
       <!-- logging -->
       <dependency>
          <groupId>org.slf4j</groupId>
@@ -80,26 +75,8 @@
       </dependency>
 
       <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-unit-test-support</artifactId>
-         <version>${project.version}</version>
-         <scope>test</scope>
-      </dependency>
-
-
-      <!-- The johnzon-core and json-api contents are repackaged in -commons,
-     However maven can still need them during tests, which run against
-     the original -commons classes when built+run in the same reactor,
-     and not the jar containing the shaded bits. -->
-      <dependency>
-         <groupId>org.apache.johnzon</groupId>
-         <artifactId>johnzon-core</artifactId>
-         <scope>test</scope>
-      </dependency>
-      <dependency>
-         <groupId>jakarta.json</groupId>
-         <artifactId>jakarta.json-api</artifactId>
-         <scope>test</scope>
+         <groupId>org.slf4j</groupId>
+         <artifactId>slf4j-api</artifactId>
       </dependency>
    </dependencies>
 
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientResource.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientDelegate.java
similarity index 78%
rename from artemis-junit/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientResource.java
rename to artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientDelegate.java
index 9d2d9418b1..9f018bb1d1 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientResource.java
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/AbstractActiveMQClientDelegate.java
@@ -24,11 +24,10 @@ import org.apache.activemq.artemis.api.core.client.ClientMessage;
 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.junit.rules.ExternalResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractActiveMQClientResource extends ExternalResource {
+public abstract class AbstractActiveMQClientDelegate {
 
    Logger log = LoggerFactory.getLogger(this.getClass());
 
@@ -40,33 +39,37 @@ public abstract class AbstractActiveMQClientResource extends ExternalResource {
    String username;
    String password;
 
-   public AbstractActiveMQClientResource(String url, String username, String password) {
+   public AbstractActiveMQClientDelegate(String url, String username, String password) {
       this(url);
       this.username = username;
       this.password = password;
    }
 
-   public AbstractActiveMQClientResource(String url) {
+   public AbstractActiveMQClientDelegate(String url) {
       if (url == null) {
-         throw new IllegalArgumentException(String.format("Error creating %s - url cannot be null", this.getClass().getSimpleName()));
+         throw new IllegalArgumentException(String.format("Error creating %s - url cannot be null",
+                                                          this.getClass().getSimpleName()));
       }
 
       try {
          this.serverLocator = ActiveMQClient.createServerLocator(url);
       } catch (Exception ex) {
-         throw new RuntimeException(String.format("Error creating %s - createServerLocator( %s ) failed", this.getClass().getSimpleName(), url), ex);
+         throw new RuntimeException(String.format("Error creating %s - createServerLocator( %s ) failed",
+                                                  this.getClass().getSimpleName(), url),
+                                    ex);
       }
    }
 
-   public AbstractActiveMQClientResource(ServerLocator serverLocator, String username, String password) {
+   public AbstractActiveMQClientDelegate(ServerLocator serverLocator, String username, String password) {
       this(serverLocator);
       this.username = username;
       this.password = password;
    }
 
-   public AbstractActiveMQClientResource(ServerLocator serverLocator) {
+   public AbstractActiveMQClientDelegate(ServerLocator serverLocator) {
       if (serverLocator == null) {
-         throw new IllegalArgumentException(String.format("Error creating %s - ServerLocator cannot be null", this.getClass().getSimpleName()));
+         throw new IllegalArgumentException(String.format("Error creating %s - ServerLocator cannot be null",
+                                                          this.getClass().getSimpleName()));
       }
 
       this.serverLocator = serverLocator;
@@ -74,7 +77,6 @@ public abstract class AbstractActiveMQClientResource extends ExternalResource {
 
    /**
     * Adds properties to a ClientMessage
-    *
     * @param message
     * @param properties
     */
@@ -86,27 +88,18 @@ public abstract class AbstractActiveMQClientResource extends ExternalResource {
       }
    }
 
-   @Override
-   protected void before() throws Throwable {
-      super.before();
-      start();
-   }
-
-   @Override
-   protected void after() {
-      stop();
-      super.after();
-   }
-
    void start() {
       log.info("Starting {}", this.getClass().getSimpleName());
       try {
          sessionFactory = serverLocator.createSessionFactory();
-         session = sessionFactory.createSession(username, password, false, true, true, serverLocator.isPreAcknowledge(), serverLocator.getAckBatchSize());
+         session = sessionFactory.createSession(username, password, false, true, true, serverLocator.isPreAcknowledge(),
+                                                serverLocator.getAckBatchSize());
       } catch (RuntimeException runtimeEx) {
          throw runtimeEx;
       } catch (Exception ex) {
-         throw new ActiveMQClientResourceException(String.format("%s initialisation failure", this.getClass().getSimpleName()), ex);
+         throw new ActiveMQClientResourceException(String.format("%s initialisation failure",
+                                                                 this.getClass().getSimpleName()),
+                                                   ex);
       }
 
       createClient();
@@ -114,7 +107,8 @@ public abstract class AbstractActiveMQClientResource extends ExternalResource {
       try {
          session.start();
       } catch (ActiveMQException amqEx) {
-         throw new ActiveMQClientResourceException(String.format("%s startup failure", this.getClass().getSimpleName()), amqEx);
+         throw new ActiveMQClientResourceException(String.format("%s startup failure", this.getClass().getSimpleName()),
+                                                   amqEx);
       }
    }
 
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerDelegate.java
similarity index 66%
rename from artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
rename to artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerDelegate.java
index 8e8428ada6..8e1deed270 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerResource.java
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerDelegate.java
@@ -25,74 +25,56 @@ import org.apache.activemq.artemis.api.core.client.ServerLocator;
 import org.apache.activemq.artemis.api.core.RoutingType;
 
 /**
- * A JUnit Rule that embeds an ActiveMQ Artemis ClientConsumer into a test.
- *
- * This JUnit Rule is designed to simplify using ActiveMQ Artemis clients in unit tests.  Adding the rule to a test will startup
- * a ClientConsumer, which can then be used to consume messages from an ActiveMQ Artemis server.
- *
- * <pre><code>
- * public class SimpleTest {
- *     &#64;Rule
- *     public ActiveMQConsumerResource client = new ActiveMQProducerResource( "vm://0", "test.queue" );
- *
- *     &#64;Test
- *     public void testSomething() throws Exception {
- *         // Use the embedded client here
- *         ClientMessage message = client.receiveMessage();
- *     }
- * }
- * </code></pre>
+ * Base class to embed an ActiveMQ Artemis ClientConsumer into a test.
  */
-public class ActiveMQConsumerResource extends AbstractActiveMQClientResource {
+public class ActiveMQConsumerDelegate extends AbstractActiveMQClientDelegate implements ActiveMQConsumerOperations {
 
    long defaultReceiveTimeout = 50;
 
    SimpleString queueName;
    ClientConsumer consumer;
 
-   public ActiveMQConsumerResource(String url, String queueName) {
+   public ActiveMQConsumerDelegate(String url, String queueName) {
       this(url, SimpleString.toSimpleString(queueName), null, null);
    }
 
-   public ActiveMQConsumerResource(String url, String queueName, String username, String password) {
+   public ActiveMQConsumerDelegate(String url, String queueName, String username, String password) {
       this(url, SimpleString.toSimpleString(queueName), username, password);
    }
 
-   public ActiveMQConsumerResource(String url, SimpleString queueName, String username, String password) {
+   public ActiveMQConsumerDelegate(String url, SimpleString queueName, String username, String password) {
       super(url, username, password);
       this.queueName = queueName;
    }
 
-   public ActiveMQConsumerResource(String url, SimpleString queueName) {
+   public ActiveMQConsumerDelegate(String url, SimpleString queueName) {
       this(url, queueName, null, null);
    }
 
-   public ActiveMQConsumerResource(ServerLocator serverLocator, String queueName, String username, String password) {
+   public ActiveMQConsumerDelegate(ServerLocator serverLocator, String queueName, String username, String password) {
       this(serverLocator, SimpleString.toSimpleString(queueName), username, password);
    }
 
-   public ActiveMQConsumerResource(ServerLocator serverLocator, String queueName) {
+   public ActiveMQConsumerDelegate(ServerLocator serverLocator, String queueName) {
       this(serverLocator, SimpleString.toSimpleString(queueName), null, null);
    }
 
-   public ActiveMQConsumerResource(ServerLocator serverLocator, SimpleString queueName, String username, String password) {
+   public ActiveMQConsumerDelegate(ServerLocator serverLocator, SimpleString queueName, String username,
+                                   String password) {
       super(serverLocator, username, password);
       this.queueName = queueName;
    }
 
-   public ActiveMQConsumerResource(ServerLocator serverLocator, SimpleString queueName) {
+   public ActiveMQConsumerDelegate(ServerLocator serverLocator, SimpleString queueName) {
       this(serverLocator, queueName, null, null);
    }
 
+   @Override
    public long getDefaultReceiveTimeout() {
       return defaultReceiveTimeout;
    }
 
-   /**
-    * Sets the default timeout in milliseconds used when receiving messages.  Defaults to 50 milliseconds
-    *
-    * @param defaultReceiveTimeout received timeout in milliseconds
-    */
+   @Override
    public void setDefaultReceiveTimeout(long defaultReceiveTimeout) {
       this.defaultReceiveTimeout = defaultReceiveTimeout;
    }
@@ -102,13 +84,16 @@ public class ActiveMQConsumerResource extends AbstractActiveMQClientResource {
       boolean browseOnly = false;
       try {
          if (!session.queueQuery(queueName).isExists() && autoCreateQueue) {
-            log.warn("{}: queue does not exist - creating queue: address = {}, name = {}", this.getClass().getSimpleName(), queueName.toString(), queueName.toString());
+            log.warn("{}: queue does not exist - creating queue: address = {}, name = {}",
+                     this.getClass().getSimpleName(), queueName.toString(), queueName.toString());
             session.createAddress(queueName, RoutingType.MULTICAST, true);
             session.createQueue(new QueueConfiguration(queueName));
          }
          consumer = session.createConsumer(queueName, browseOnly);
       } catch (ActiveMQException amqEx) {
-         throw new ActiveMQClientResourceException(String.format("Error creating consumer for queueName %s", queueName.toString()), amqEx);
+         throw new ActiveMQClientResourceException(String.format("Error creating consumer for queueName %s",
+                                                                 queueName.toString()),
+                                                   amqEx);
       }
    }
 
@@ -130,39 +115,43 @@ public class ActiveMQConsumerResource extends AbstractActiveMQClientResource {
       return autoCreateQueue;
    }
 
-   /**
-    * Enable/Disable the automatic creation of non-existent queues.  The default is to automatically create non-existent queues
-    *
-    * @param autoCreateQueue
-    */
    @Override
    public void setAutoCreateQueue(boolean autoCreateQueue) {
       this.autoCreateQueue = autoCreateQueue;
    }
 
+   @Override
    public ClientMessage receiveMessage() {
       return receiveMessage(defaultReceiveTimeout);
    }
 
+   @Override
    public ClientMessage receiveMessage(long timeout) {
       ClientMessage message = null;
       if (timeout > 0) {
          try {
             message = consumer.receive(timeout);
          } catch (ActiveMQException amqEx) {
-            throw new EmbeddedActiveMQResource.EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive( timeout = %d ) for %s failed", timeout, queueName.toString()), amqEx);
+            throw new EmbeddedActiveMQDelegate.EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive( timeout = %d ) for %s failed",
+                                                                                               timeout,
+                                                                                               queueName.toString()),
+                                                                                 amqEx);
          }
       } else if (timeout == 0) {
          try {
             message = consumer.receiveImmediate();
          } catch (ActiveMQException amqEx) {
-            throw new EmbeddedActiveMQResource.EmbeddedActiveMQResourceException(String.format("ClientConsumer.receiveImmediate() for %s failed", queueName.toString()), amqEx);
+            throw new EmbeddedActiveMQDelegate.EmbeddedActiveMQResourceException(String.format("ClientConsumer.receiveImmediate() for %s failed",
+                                                                                               queueName.toString()),
+                                                                                 amqEx);
          }
       } else {
          try {
             message = consumer.receive();
          } catch (ActiveMQException amqEx) {
-            throw new EmbeddedActiveMQResource.EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive() for %s failed", queueName.toString()), amqEx);
+            throw new EmbeddedActiveMQDelegate.EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive() for %s failed",
+                                                                                               queueName.toString()),
+                                                                                 amqEx);
          }
       }
 
diff --git a/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerOperations.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerOperations.java
new file mode 100644
index 0000000000..0b82adb776
--- /dev/null
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQConsumerOperations.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.activemq.artemis.junit;
+
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+
+public interface ActiveMQConsumerOperations {
+
+   long getDefaultReceiveTimeout();
+
+   /**
+    * Sets the default timeout in milliseconds used when receiving messages. Defaults to 50
+    * milliseconds
+    * @param defaultReceiveTimeout received timeout in milliseconds
+    */
+   void setDefaultReceiveTimeout(long defaultReceiveTimeout);
+
+   boolean isAutoCreateQueue();
+
+   /**
+    * Enable/Disable the automatic creation of non-existent queues. The default is to automatically
+    * create non-existent queues
+    * @param autoCreateQueue
+    */
+   void setAutoCreateQueue(boolean autoCreateQueue);
+
+   ClientMessage receiveMessage();
+
+   ClientMessage receiveMessage(long timeout);
+
+}
\ No newline at end of file
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResource.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerDelegate.java
similarity index 55%
rename from artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResource.java
rename to artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerDelegate.java
index 027ada94d0..0185df80b6 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerResource.java
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerDelegate.java
@@ -25,55 +25,41 @@ import org.apache.activemq.artemis.api.core.client.ClientMessage;
 import org.apache.activemq.artemis.api.core.client.ServerLocator;
 
 /**
- * A JUnit Rule that embeds an dynamic (i.e. unbound) ActiveMQ Artemis ClientProducer into a test.
- *
- * This JUnit Rule is designed to simplify using ActiveMQ Artemis clients in unit tests.  Adding the rule to a test will startup
- * an unbound ClientProducer, which can then be used to feed messages to any address on the ActiveMQ Artemis server.
- *
- * <pre><code>
- * public class SimpleTest {
- *     &#64;Rule
- *     public ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource( "vm://0");
- *
- *     &#64;Test
- *     public void testSomething() throws Exception {
- *         // Use the embedded ClientProducer here
- *         producer.sendMessage( "test.address", "String Body" );
- *     }
- * }
- * </code></pre>
+ * Base class to embed an dynamic (i.e. unbound) ActiveMQ Artemis ClientProducer into a test.
  */
-public class ActiveMQDynamicProducerResource extends ActiveMQProducerResource {
+public class ActiveMQDynamicProducerDelegate extends ActiveMQProducerDelegate
+         implements ActiveMQDynamicProducerOperations {
 
-   public ActiveMQDynamicProducerResource(String url, String username, String password) {
+   public ActiveMQDynamicProducerDelegate(String url, String username, String password) {
       super(url, username, password);
    }
 
-   public ActiveMQDynamicProducerResource(String url) {
+   public ActiveMQDynamicProducerDelegate(String url) {
       super(url);
    }
 
-   public ActiveMQDynamicProducerResource(ServerLocator serverLocator, String username, String password) {
+   public ActiveMQDynamicProducerDelegate(ServerLocator serverLocator, String username, String password) {
       super(serverLocator, username, password);
    }
 
-   public ActiveMQDynamicProducerResource(ServerLocator serverLocator) {
+   public ActiveMQDynamicProducerDelegate(ServerLocator serverLocator) {
       super(serverLocator);
    }
 
-   public ActiveMQDynamicProducerResource(String url, SimpleString address, String username, String password) {
+   public ActiveMQDynamicProducerDelegate(String url, SimpleString address, String username, String password) {
       super(url, address, username, password);
    }
 
-   public ActiveMQDynamicProducerResource(String url, SimpleString address) {
+   public ActiveMQDynamicProducerDelegate(String url, SimpleString address) {
       super(url, address);
    }
 
-   public ActiveMQDynamicProducerResource(ServerLocator serverLocator, SimpleString address, String username, String password) {
+   public ActiveMQDynamicProducerDelegate(ServerLocator serverLocator, SimpleString address, String username,
+                                          String password) {
       super(serverLocator, address, username, password);
    }
 
-   public ActiveMQDynamicProducerResource(ServerLocator serverLocator, SimpleString address) {
+   public ActiveMQDynamicProducerDelegate(ServerLocator serverLocator, SimpleString address) {
       super(serverLocator, address);
    }
 
@@ -81,114 +67,82 @@ public class ActiveMQDynamicProducerResource extends ActiveMQProducerResource {
    protected void createClient() {
       try {
          if (address != null && !session.addressQuery(address).isExists() && autoCreateQueue) {
-            log.warn("queue does not exist - creating queue: address = {}, name = {}", address.toString(), address.toString());
+            log.warn("queue does not exist - creating queue: address = {}, name = {}", address.toString(),
+                     address.toString());
             session.createQueue(new QueueConfiguration(address));
          }
          producer = session.createProducer((SimpleString) null);
       } catch (ActiveMQException amqEx) {
          if (address == null) {
-            throw new ActiveMQClientResourceException(String.format("Error creating producer for address %s", address.toString()), amqEx);
+            throw new ActiveMQClientResourceException(String.format("Error creating producer for address %s",
+                                                                    address.toString()),
+                                                      amqEx);
          } else {
             throw new ActiveMQClientResourceException("Error creating producer", amqEx);
          }
       }
    }
 
-   /**
-    * Send a ClientMessage to the default address on the server
-    *
-    * @param message the message to send
-    */
    @Override
    public void sendMessage(ClientMessage message) {
       sendMessage(address, message);
    }
 
-   /**
-    * Send a ClientMessage to the specified address on the server
-    *
-    * @param targetAddress the target address
-    * @param message       the message to send
-    */
+   @Override
    public void sendMessage(SimpleString targetAddress, ClientMessage message) {
       if (targetAddress == null) {
-         throw new IllegalArgumentException(String.format("%s error - address cannot be null", this.getClass().getSimpleName()));
+         throw new IllegalArgumentException(String.format("%s error - address cannot be null",
+                                                          this.getClass().getSimpleName()));
       }
       try {
          if (autoCreateQueue && !session.addressQuery(targetAddress).isExists()) {
-            log.warn("queue does not exist - creating queue: address = {}, name = {}", address.toString(), address.toString());
+            log.warn("queue does not exist - creating queue: address = {}, name = {}", address.toString(),
+                     address.toString());
             session.createQueue(new QueueConfiguration(targetAddress));
          }
       } catch (ActiveMQException amqEx) {
-         throw new ActiveMQClientResourceException(String.format("Queue creation failed for queue: address = %s, name = %s", address.toString(), address.toString()));
+         throw new ActiveMQClientResourceException(String.format("Queue creation failed for queue: address = %s, name = %s",
+                                                                 address.toString(), address.toString()));
       }
 
       try {
          producer.send(targetAddress, message);
       } catch (ActiveMQException amqEx) {
-         throw new ActiveMQClientResourceException(String.format("Failed to send message to %s", targetAddress.toString()), amqEx);
+         throw new ActiveMQClientResourceException(String.format("Failed to send message to %s",
+                                                                 targetAddress.toString()),
+                                                   amqEx);
       }
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and send to the specified address on the server
-    *
-    * @param targetAddress the target address
-    * @param body          the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString targetAddress, byte[] body) {
       ClientMessage message = createMessage(body);
       sendMessage(targetAddress, message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and send to the server
-    *
-    * @param targetAddress the target address
-    * @param body          the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString targetAddress, String body) {
       ClientMessage message = createMessage(body);
       sendMessage(targetAddress, message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified properties and send to the server
-    *
-    * @param targetAddress the target address
-    * @param properties    the properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString targetAddress, Map<String, Object> properties) {
       ClientMessage message = createMessage(properties);
       sendMessage(targetAddress, message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and and properties and send to the server
-    *
-    * @param targetAddress the target address
-    * @param properties    the properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString targetAddress, byte[] body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
       sendMessage(targetAddress, message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and and properties and send to the server
-    *
-    * @param targetAddress the target address
-    * @param properties    the properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString targetAddress, String body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
       sendMessage(targetAddress, message);
diff --git a/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerOperations.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerOperations.java
new file mode 100644
index 0000000000..f9b46d4b2f
--- /dev/null
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQDynamicProducerOperations.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+
+public interface ActiveMQDynamicProducerOperations {
+
+   /**
+    * Send a ClientMessage to the default address on the server
+    * @param message the message to send
+    */
+   void sendMessage(ClientMessage message);
+
+   /**
+    * Send a ClientMessage to the specified address on the server
+    * @param targetAddress the target address
+    * @param message the message to send
+    */
+   void sendMessage(SimpleString targetAddress, ClientMessage message);
+
+   /**
+    * Create a new ClientMessage with the specified body and send to the specified address on the
+    * server
+    * @param targetAddress the target address
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString targetAddress, byte[] body);
+
+   /**
+    * Create a new ClientMessage with the specified body and send to the server
+    * @param targetAddress the target address
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString targetAddress, String body);
+
+   /**
+    * Create a new ClientMessage with the specified properties and send to the server
+    * @param targetAddress the target address
+    * @param properties the properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString targetAddress, Map<String, Object> properties);
+
+   /**
+    * Create a new ClientMessage with the specified body and and properties and send to the server
+    * @param targetAddress the target address
+    * @param properties the properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString targetAddress, byte[] body, Map<String, Object> properties);
+
+   /**
+    * Create a new ClientMessage with the specified body and and properties and send to the server
+    * @param targetAddress the target address
+    * @param properties the properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString targetAddress, String body, Map<String, Object> properties);
+
+}
\ No newline at end of file
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerDelegate.java
similarity index 51%
rename from artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java
rename to artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerDelegate.java
index 75d413e57f..8619d5ffc3 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerResource.java
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerDelegate.java
@@ -26,95 +26,79 @@ import org.apache.activemq.artemis.api.core.client.ClientProducer;
 import org.apache.activemq.artemis.api.core.client.ServerLocator;
 
 /**
- * A JUnit Rule that embeds an ActiveMQ Artemis ClientProducer bound to a specific address into a test.
- *
- * This JUnit Rule is designed to simplify using ActiveMQ Artemis clients in unit tests.  Adding the rule to a test will startup
- * a ClientProducer, which can then be used to feed messages to the bound address on an ActiveMQ Artemis server.
- *
- * <pre><code>
- * public class SimpleTest {
- *     &#64;Rule
- *     public ActiveMQProducerResource producer = new ActiveMQProducerResource( "vm://0", "test.queue");
- *
- *     &#64;Test
- *     public void testSomething() throws Exception {
- *         // Use the embedded ClientProducer here
- *         producer.sendMessage( "String Body" );
- *     }
- * }
- * </code></pre>
+ * Base class to embed an ActiveMQ Artemis ClientProducer bound to a specific address into a test.
  */
-public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
+public class ActiveMQProducerDelegate extends AbstractActiveMQClientDelegate implements ActiveMQProducerOperations {
 
    boolean useDurableMessage = true;
    SimpleString address = null;
    ClientProducer producer;
 
-   protected ActiveMQProducerResource(String url, String username, String password) {
+   protected ActiveMQProducerDelegate(String url, String username, String password) {
       super(url, username, password);
    }
 
-   protected ActiveMQProducerResource(String url) {
+   protected ActiveMQProducerDelegate(String url) {
       super(url);
    }
 
-   protected ActiveMQProducerResource(ServerLocator serverLocator, String username, String password) {
+   protected ActiveMQProducerDelegate(ServerLocator serverLocator, String username, String password) {
       super(serverLocator, username, password);
    }
 
-   protected ActiveMQProducerResource(ServerLocator serverLocator) {
+   protected ActiveMQProducerDelegate(ServerLocator serverLocator) {
       super(serverLocator);
    }
 
-   public ActiveMQProducerResource(String url, String address, String username, String password) {
+   protected ActiveMQProducerDelegate(String url, String address, String username, String password) {
       this(url, SimpleString.toSimpleString(address), username, password);
    }
 
-   public ActiveMQProducerResource(String url, String address) {
+   protected ActiveMQProducerDelegate(String url, String address) {
       this(url, address, null, null);
    }
 
-   public ActiveMQProducerResource(String url, SimpleString address, String username, String password) {
+   protected ActiveMQProducerDelegate(String url, SimpleString address, String username, String password) {
       super(url, username, password);
       if (address == null) {
-         throw new IllegalArgumentException(String.format("%s construction error - address cannot be null", this.getClass().getSimpleName()));
+         throw new IllegalArgumentException(String.format("%s construction error - address cannot be null",
+                                                          this.getClass().getSimpleName()));
       }
       this.address = address;
    }
 
-   public ActiveMQProducerResource(String url, SimpleString address) {
+   protected ActiveMQProducerDelegate(String url, SimpleString address) {
       this(url, address, null, null);
    }
 
-   public ActiveMQProducerResource(ServerLocator serverLocator, String address, String username, String password) {
+   protected ActiveMQProducerDelegate(ServerLocator serverLocator, String address, String username, String password) {
       this(serverLocator, SimpleString.toSimpleString(address), username, password);
    }
 
-   public ActiveMQProducerResource(ServerLocator serverLocator, String address) {
+   protected ActiveMQProducerDelegate(ServerLocator serverLocator, String address) {
       this(serverLocator, SimpleString.toSimpleString(address));
    }
 
-   public ActiveMQProducerResource(ServerLocator serverLocator, SimpleString address, String username, String password) {
+   protected ActiveMQProducerDelegate(ServerLocator serverLocator, SimpleString address, String username,
+                                      String password) {
       super(serverLocator, username, password);
       if (address == null) {
-         throw new IllegalArgumentException(String.format("%s construction error - address cannot be null", this.getClass().getSimpleName()));
+         throw new IllegalArgumentException(String.format("%s construction error - address cannot be null",
+                                                          this.getClass().getSimpleName()));
       }
       this.address = address;
    }
 
-   public ActiveMQProducerResource(ServerLocator serverLocator, SimpleString address) {
+   protected ActiveMQProducerDelegate(ServerLocator serverLocator, SimpleString address) {
       this(serverLocator, address, null, null);
    }
 
+   @Override
    public boolean isUseDurableMessage() {
       return useDurableMessage;
    }
 
-   /**
-    * Disables/Enables creating durable messages.  By default, durable messages are created
-    *
-    * @param useDurableMessage if true, durable messages will be created
-    */
+   @Override
    public void setUseDurableMessage(boolean useDurableMessage) {
       this.useDurableMessage = useDurableMessage;
    }
@@ -123,12 +107,15 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
    protected void createClient() {
       try {
          if (!session.addressQuery(address).isExists() && autoCreateQueue) {
-            log.warn("{}: queue does not exist - creating queue: address = {}, name = {}", this.getClass().getSimpleName(), address.toString(), address.toString());
+            log.warn("{}: queue does not exist - creating queue: address = {}, name = {}",
+                     this.getClass().getSimpleName(), address.toString(), address.toString());
             session.createQueue(new QueueConfiguration(address));
          }
          producer = session.createProducer(address);
       } catch (ActiveMQException amqEx) {
-         throw new ActiveMQClientResourceException(String.format("Error creating producer for address %s", address.toString()), amqEx);
+         throw new ActiveMQClientResourceException(String.format("Error creating producer for address %s",
+                                                                 address.toString()),
+                                                   amqEx);
       }
    }
 
@@ -145,13 +132,7 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       }
    }
 
-   /**
-    * Create a ClientMessage
-    * <p>
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @return a new ClientMessage
-    */
+   @Override
    public ClientMessage createMessage() {
       if (session == null) {
          throw new IllegalStateException("ClientSession is null");
@@ -159,14 +140,7 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       return session.createMessage(isUseDurableMessage());
    }
 
-   /**
-    * Create a ClientMessage with the specified body
-    * <p>
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body the body for the new message
-    * @return a new ClientMessage with the specified body
-    */
+   @Override
    public ClientMessage createMessage(byte[] body) {
       ClientMessage message = createMessage();
 
@@ -177,14 +151,7 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified body
-    * <p>
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body the body for the new message
-    * @return a new ClientMessage with the specified body
-    */
+   @Override
    public ClientMessage createMessage(String body) {
       ClientMessage message = createMessage();
 
@@ -195,14 +162,7 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified message properties
-    * <p>
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param properties message properties for the new message
-    * @return a new ClientMessage with the specified message properties
-    */
+   @Override
    public ClientMessage createMessage(Map<String, Object> properties) {
       ClientMessage message = createMessage();
 
@@ -211,15 +171,7 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified body and message properties
-    * <p>
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return a new ClientMessage with the specified body and message properties
-    */
+   @Override
    public ClientMessage createMessage(byte[] body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
 
@@ -228,15 +180,7 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified body and message properties
-    * <p>
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return a new ClientMessage with the specified body and message properties
-    */
+   @Override
    public ClientMessage createMessage(String body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
 
@@ -245,73 +189,46 @@ public class ActiveMQProducerResource extends AbstractActiveMQClientResource {
       return message;
    }
 
-   /**
-    * Send a ClientMessage to the server
-    *
-    * @param message the message to send
-    */
+   @Override
    public void sendMessage(ClientMessage message) {
       try {
          producer.send(message);
       } catch (ActiveMQException amqEx) {
-         throw new ActiveMQClientResourceException(String.format("Failed to send message to %s", producer.getAddress().toString()), amqEx);
+         throw new ActiveMQClientResourceException(String.format("Failed to send message to %s",
+                                                                 producer.getAddress().toString()),
+                                                   amqEx);
       }
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and send to the server
-    *
-    * @param body the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(byte[] body) {
       ClientMessage message = createMessage(body);
       sendMessage(message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and send to the server
-    *
-    * @param body the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(String body) {
       ClientMessage message = createMessage(body);
       sendMessage(message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified properties and send to the server
-    *
-    * @param properties the properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(Map<String, Object> properties) {
       ClientMessage message = createMessage(properties);
       sendMessage(message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and and properties and send to the server
-    *
-    * @param properties the properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(byte[] body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
       sendMessage(message);
       return message;
    }
 
-   /**
-    * Create a new ClientMessage with the specified body and and properties and send to the server
-    *
-    * @param properties the properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(String body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
       sendMessage(message);
diff --git a/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerOperations.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerOperations.java
new file mode 100644
index 0000000000..2ec01a3273
--- /dev/null
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/ActiveMQProducerOperations.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.activemq.artemis.junit;
+
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+
+public interface ActiveMQProducerOperations {
+
+   boolean isUseDurableMessage();
+
+   /**
+    * Disables/Enables creating durable messages. By default, durable messages are created.
+    * @param useDurableMessage if true, durable messages will be created
+    */
+   void setUseDurableMessage(boolean useDurableMessage);
+
+   /**
+    * Create a ClientMessage.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @return a new ClientMessage
+    */
+   ClientMessage createMessage();
+
+   /**
+    * Create a ClientMessage with the specified body.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @return a new ClientMessage with the specified body
+    */
+   ClientMessage createMessage(byte[] body);
+
+   /**
+    * Create a ClientMessage with the specified body.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @return a new ClientMessage with the specified body
+    */
+   ClientMessage createMessage(String body);
+
+   /**
+    * Create a ClientMessage with the specified message properties.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param properties message properties for the new message
+    * @return a new ClientMessage with the specified message properties
+    */
+   ClientMessage createMessage(Map<String, Object> properties);
+
+   /**
+    * Create a ClientMessage with the specified body and message properties.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return a new ClientMessage with the specified body and message properties
+    */
+   ClientMessage createMessage(byte[] body, Map<String, Object> properties);
+
+   /**
+    * Create a ClientMessage with the specified body and message properties.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return a new ClientMessage with the specified body and message properties
+    */
+   ClientMessage createMessage(String body, Map<String, Object> properties);
+
+   /**
+    * Send a ClientMessage to the server.
+    * @param message the message to send
+    */
+   void sendMessage(ClientMessage message);
+
+   /**
+    * Create a new ClientMessage with the specified body and send to the server.
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(byte[] body);
+
+   /**
+    * Create a new ClientMessage with the specified body and send to the server.
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(String body);
+
+   /**
+    * Create a new ClientMessage with the specified properties and send to the server
+    * @param properties the properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(Map<String, Object> properties);
+
+   /**
+    * Create a new ClientMessage with the specified body and and properties and send to the server
+    * @param properties the properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(byte[] body, Map<String, Object> properties);
+
+   /**
+    * Create a new ClientMessage with the specified body and and properties and send to the server
+    * @param properties the properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(String body, Map<String, Object> properties);
+
+}
\ No newline at end of file
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQDelegate.java
similarity index 61%
rename from artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java
rename to artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQDelegate.java
index 461173e4ff..028378b7c5 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQResource.java
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQDelegate.java
@@ -43,30 +43,14 @@ import org.apache.activemq.artemis.core.server.Queue;
 import org.apache.activemq.artemis.api.core.RoutingType;
 import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
-import org.junit.rules.ExternalResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import java.lang.invoke.MethodHandles;
 
 /**
- * A JUnit Rule that embeds an ActiveMQ Artemis server into a test.
- *
- * This JUnit Rule is designed to simplify using embedded servers in unit tests.  Adding the rule to a test will startup
- * an embedded server, which can then be used by client applications.
- *
- * <pre><code>
- * public class SimpleTest {
- *     &#64;Rule
- *     public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
- *
- *     &#64;Test
- *     public void testSomething() throws Exception {
- *         // Use the embedded server here
- *     }
- * }
- * </code></pre>
+ * Base class to embed an ActiveMQ Artemis server into a test.
  */
-public class EmbeddedActiveMQResource extends ExternalResource {
+public class EmbeddedActiveMQDelegate implements EmbeddedActiveMQOperations {
    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
    static final String SERVER_NAME = "embedded-server";
@@ -84,40 +68,48 @@ public class EmbeddedActiveMQResource extends ExternalResource {
    /**
     * Create a default EmbeddedActiveMQResource
     */
-   public EmbeddedActiveMQResource() {
-      configuration = new ConfigurationImpl().setName(SERVER_NAME).setPersistenceEnabled(false).setSecurityEnabled(false).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName())).addAddressSetting("#", new AddressSettings().setDeadLetterAddress(SimpleString.toSimpleString("dla")).setExpiryAddress(SimpleString.toSimpleString("expiry")));
+   protected EmbeddedActiveMQDelegate() {
+      configuration =
+               new ConfigurationImpl().setName(SERVER_NAME)
+                                      .setPersistenceEnabled(false)
+                                      .setSecurityEnabled(false)
+                                      .addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName()))
+                                      .addAddressSetting("#",
+                                                         new AddressSettings().setDeadLetterAddress(SimpleString.toSimpleString("dla"))
+                                                                              .setExpiryAddress(SimpleString.toSimpleString("expiry")));
       init();
    }
 
    /**
     * Create a default EmbeddedActiveMQResource with the specified serverId
-    *
     * @param serverId server id
     */
-   public EmbeddedActiveMQResource(int serverId) {
+   protected EmbeddedActiveMQDelegate(int serverId) {
       Map<String, Object> params = new HashMap<>();
       params.put(TransportConstants.SERVER_ID_PROP_NAME, serverId);
-      TransportConfiguration transportConfiguration = new TransportConfiguration(InVMAcceptorFactory.class.getName(), params);
-      configuration = new ConfigurationImpl().setName(SERVER_NAME + "-" + serverId).setPersistenceEnabled(false).setSecurityEnabled(false).addAcceptorConfiguration(transportConfiguration);
+      TransportConfiguration transportConfiguration =
+               new TransportConfiguration(InVMAcceptorFactory.class.getName(), params);
+      configuration = new ConfigurationImpl().setName(SERVER_NAME + "-" + serverId)
+                                             .setPersistenceEnabled(false)
+                                             .setSecurityEnabled(false)
+                                             .addAcceptorConfiguration(transportConfiguration);
       init();
    }
 
    /**
     * Creates an EmbeddedActiveMQResource using the specified configuration
-    *
     * @param configuration ActiveMQServer configuration
     */
-   public EmbeddedActiveMQResource(Configuration configuration) {
+   protected EmbeddedActiveMQDelegate(Configuration configuration) {
       this.configuration = configuration;
       init();
    }
 
    /**
     * Creates an EmbeddedActiveMQResource using the specified configuration file
-    *
     * @param filename ActiveMQServer configuration file name
     */
-   public EmbeddedActiveMQResource(String filename) {
+   protected EmbeddedActiveMQDelegate(String filename) {
       if (filename == null) {
          throw new IllegalArgumentException("ActiveMQServer configuration file name cannot be null");
       }
@@ -127,7 +119,8 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       try {
          deploymentManager.readConfiguration();
       } catch (Exception ex) {
-         throw new EmbeddedActiveMQResourceException(String.format("Failed to read configuration file %s", filename), ex);
+         throw new EmbeddedActiveMQResourceException(String.format("Failed to read configuration file %s", filename),
+                                                     ex);
       }
       this.configuration = config;
       init();
@@ -135,7 +128,6 @@ public class EmbeddedActiveMQResource extends ExternalResource {
 
    /**
     * Adds properties to a ClientMessage
-    *
     * @param message
     * @param properties
     */
@@ -153,28 +145,20 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       }
    }
 
-   /**
-    * Start the embedded ActiveMQ Artemis server.
-    *
-    * The server will normally be started by JUnit using the before() method.  This method allows the server to
-    * be started manually to support advanced testing scenarios.
-    */
+   @Override
    public void start() {
       try {
          server.start();
       } catch (Exception ex) {
-         throw new RuntimeException(String.format("Exception encountered starting %s: %s", server.getClass().getName(), this.getServerName()), ex);
+         throw new RuntimeException(String.format("Exception encountered starting %s: %s", server.getClass().getName(),
+                                                  this.getServerName()),
+                                    ex);
       }
 
       configuration = server.getActiveMQServer().getConfiguration();
    }
 
-   /**
-    * Stop the embedded ActiveMQ Artemis server
-    *
-    * The server will normally be stopped by JUnit using the after() method.  This method allows the server to
-    * be stopped manually to support advanced testing scenarios.
-    */
+   @Override
    public void stop() {
       if (internalClient != null) {
          internalClient.stop();
@@ -190,85 +174,42 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       }
    }
 
-   /**
-    * Invoked by JUnit to setup the resource - start the embedded ActiveMQ Artemis server
-    */
-   @Override
-   protected void before() throws Throwable {
-      logger.info("Starting {}: {}", this.getClass().getSimpleName(), getServerName());
-
-      this.start();
-
-      super.before();
-   }
-
-   /**
-    * Invoked by JUnit to tear down the resource - stops the embedded ActiveMQ Artemis server
-    */
    @Override
-   protected void after() {
-      logger.info("Stopping {}: {}", this.getClass().getSimpleName(), getServerName());
-
-      this.stop();
-
-      super.after();
-   }
-
    public boolean isUseDurableMessage() {
       return useDurableMessage;
    }
 
-   /**
-    * Disables/Enables creating durable messages.  By default, durable messages are created
-    *
-    * @param useDurableMessage if true, durable messages will be created
-    */
+   @Override
    public void setUseDurableMessage(boolean useDurableMessage) {
       this.useDurableMessage = useDurableMessage;
    }
 
+   @Override
    public boolean isUseDurableQueue() {
       return useDurableQueue;
    }
 
-   /**
-    * Disables/Enables creating durable queues.  By default, durable queues are created
-    *
-    * @param useDurableQueue if true, durable messages will be created
-    */
+   @Override
    public void setUseDurableQueue(boolean useDurableQueue) {
       this.useDurableQueue = useDurableQueue;
    }
 
+   @Override
    public long getDefaultReceiveTimeout() {
       return defaultReceiveTimeout;
    }
 
-   /**
-    * Sets the default timeout in milliseconds used when receiving messages.  Defaults to 50 milliseconds
-    *
-    * @param defaultReceiveTimeout received timeout in milliseconds
-    */
+   @Override
    public void setDefaultReceiveTimeout(long defaultReceiveTimeout) {
       this.defaultReceiveTimeout = defaultReceiveTimeout;
    }
 
-   /**
-    * Get the EmbeddedActiveMQ server.
-    *
-    * This may be required for advanced configuration of the EmbeddedActiveMQ server.
-    *
-    * @return the embedded ActiveMQ broker
-    */
+   @Override
    public EmbeddedActiveMQ getServer() {
       return server;
    }
 
-   /**
-    * Get the name of the EmbeddedActiveMQ server
-    *
-    * @return name of the embedded server
-    */
+   @Override
    public String getServerName() {
       String name = "unknown";
       ActiveMQServer activeMQServer = server.getActiveMQServer();
@@ -281,11 +222,7 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return name;
    }
 
-   /**
-    * Get the VM URL for the embedded EmbeddedActiveMQ server
-    *
-    * @return the VM URL for the embedded server
-    */
+   @Override
    public String getVmURL() {
       String vmURL = "vm://0";
       for (TransportConfiguration transportConfiguration : configuration.getAcceptorConfigurations()) {
@@ -298,16 +235,12 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return vmURL;
    }
 
+   @Override
    public long getMessageCount(String queueName) {
       return getMessageCount(SimpleString.toSimpleString(queueName));
    }
 
-   /**
-    * Get the number of messages in a specific queue.
-    *
-    * @param queueName the name of the queue
-    * @return the number of messages in the queue; -1 if queue is not found
-    */
+   @Override
    public long getMessageCount(SimpleString queueName) {
       Queue queue = locateQueue(queueName);
       if (queue == null) {
@@ -318,18 +251,22 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return queue.getMessageCount();
    }
 
+   @Override
    public Queue locateQueue(String queueName) {
       return locateQueue(SimpleString.toSimpleString(queueName));
    }
 
+   @Override
    public Queue locateQueue(SimpleString queueName) {
       return server.getActiveMQServer().locateQueue(queueName);
    }
 
+   @Override
    public List<Queue> getBoundQueues(String address) {
       return getBoundQueues(SimpleString.toSimpleString(address));
    }
 
+   @Override
    public List<Queue> getBoundQueues(SimpleString address) {
       if (address == null) {
          throw new IllegalArgumentException("getBoundQueues( address ) - address cannot be null");
@@ -340,7 +277,8 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       try {
          bindingQueryResult = server.getActiveMQServer().bindingQuery(address);
       } catch (Exception e) {
-         throw new EmbeddedActiveMQResourceException(String.format("getBoundQueues( %s ) - bindingQuery( %s ) failed", address.toString(), address.toString()));
+         throw new EmbeddedActiveMQResourceException(String.format("getBoundQueues( %s ) - bindingQuery( %s ) failed",
+                                                                   address.toString(), address.toString()));
       }
       if (bindingQueryResult.isExists()) {
          for (SimpleString queueName : bindingQueryResult.getQueueNames()) {
@@ -350,61 +288,66 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return boundQueues;
    }
 
+   @Override
    public Queue createQueue(String name) {
       return createQueue(SimpleString.toSimpleString(name), SimpleString.toSimpleString(name));
    }
 
+   @Override
    public Queue createQueue(String address, String name) {
       return createQueue(SimpleString.toSimpleString(address), SimpleString.toSimpleString(name));
    }
 
+   @Override
    public Queue createQueue(SimpleString address, SimpleString name) {
       Queue queue = null;
       try {
-         queue = server.getActiveMQServer().createQueue(new QueueConfiguration(name).setAddress(address).setDurable(isUseDurableQueue()));
+         queue = server.getActiveMQServer()
+                       .createQueue(new QueueConfiguration(name).setAddress(address).setDurable(isUseDurableQueue()));
       } catch (Exception ex) {
-         throw new EmbeddedActiveMQResourceException(String.format("Failed to create queue: queueName = %s, name = %s", address.toString(), name.toString()), ex);
+         throw new EmbeddedActiveMQResourceException(String.format("Failed to create queue: queueName = %s, name = %s",
+                                                                   address.toString(), name.toString()),
+                                                     ex);
       }
 
       return queue;
    }
 
+   @Override
    public void createSharedQueue(String name, String user) {
-      createSharedQueue(SimpleString.toSimpleString(name), SimpleString.toSimpleString(name), SimpleString.toSimpleString(user));
+      createSharedQueue(SimpleString.toSimpleString(name), SimpleString.toSimpleString(name),
+                        SimpleString.toSimpleString(user));
    }
 
+   @Override
    public void createSharedQueue(String address, String name, String user) {
-      createSharedQueue(SimpleString.toSimpleString(address), SimpleString.toSimpleString(name), SimpleString.toSimpleString(user));
+      createSharedQueue(SimpleString.toSimpleString(address), SimpleString.toSimpleString(name),
+                        SimpleString.toSimpleString(user));
    }
 
+   @Override
    public void createSharedQueue(SimpleString address, SimpleString name, SimpleString user) {
       try {
-         server.getActiveMQServer().createSharedQueue(new QueueConfiguration(name).setAddress(address).setRoutingType(RoutingType.MULTICAST).setDurable(isUseDurableQueue()).setUser(user));
+         server.getActiveMQServer()
+               .createSharedQueue(new QueueConfiguration(name).setAddress(address)
+                                                              .setRoutingType(RoutingType.MULTICAST)
+                                                              .setDurable(isUseDurableQueue())
+                                                              .setUser(user));
       } catch (Exception ex) {
-         throw new EmbeddedActiveMQResourceException(String.format("Failed to create shared queue: queueName = %s, name = %s, user = %s", address.toString(), name.toString(), user.toString()), ex);
+         throw new EmbeddedActiveMQResourceException(String.format("Failed to create shared queue: queueName = %s, name = %s, user = %s",
+                                                                   address.toString(), name.toString(),
+                                                                   user.toString()),
+                                                     ex);
       }
    }
 
-   /**
-    * Create a ClientMessage
-    *
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @return a new ClientMessage
-    */
+   @Override
    public ClientMessage createMessage() {
       getInternalClient();
       return internalClient.createMessage(isUseDurableMessage());
    }
 
-   /**
-    * Create a ClientMessage with the specified body
-    *
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body the body for the new message
-    * @return a new ClientMessage with the specified body
-    */
+   @Override
    public ClientMessage createMessage(byte[] body) {
       getInternalClient();
       ClientMessage message = internalClient.createMessage(isUseDurableMessage());
@@ -416,14 +359,7 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified body
-    *
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body the body for the new message
-    * @return a new ClientMessage with the specified body
-    */
+   @Override
    public ClientMessage createMessage(String body) {
       getInternalClient();
       ClientMessage message = internalClient.createMessage(isUseDurableMessage());
@@ -435,14 +371,7 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified message properties
-    *
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param properties message properties for the new message
-    * @return a new ClientMessage with the specified message properties
-    */
+   @Override
    public ClientMessage createMessageWithProperties(Map<String, Object> properties) {
       getInternalClient();
       ClientMessage message = internalClient.createMessage(isUseDurableMessage());
@@ -452,15 +381,7 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified body and message properties
-    *
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return a new ClientMessage with the specified body and message properties
-    */
+   @Override
    public ClientMessage createMessageWithProperties(byte[] body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
 
@@ -469,15 +390,7 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return message;
    }
 
-   /**
-    * Create a ClientMessage with the specified body and message properties
-    *
-    * If useDurableMessage is false, a non-durable message is created.  Otherwise, a durable message is created
-    *
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return a new ClientMessage with the specified body and message properties
-    */
+   @Override
    public ClientMessage createMessageWithProperties(String body, Map<String, Object> properties) {
       ClientMessage message = createMessage(body);
 
@@ -486,79 +399,37 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return message;
    }
 
-   /**
-    * Send a message to an address
-    *
-    * @param address the target queueName for the message
-    * @param message the message to send
-    */
+   @Override
    public void sendMessage(String address, ClientMessage message) {
       sendMessage(SimpleString.toSimpleString(address), message);
    }
 
-   /**
-    * Create a new message with the specified body, and send the message to an address
-    *
-    * @param address the target queueName for the message
-    * @param body    the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(String address, byte[] body) {
       return sendMessage(SimpleString.toSimpleString(address), body);
    }
 
-   /**
-    * Create a new message with the specified body, and send the message to an address
-    *
-    * @param address the target queueName for the message
-    * @param body    the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(String address, String body) {
       return sendMessage(SimpleString.toSimpleString(address), body);
    }
 
-   /**
-    * Create a new message with the specified properties, and send the message to an address
-    *
-    * @param address    the target queueName for the message
-    * @param properties message properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessageWithProperties(String address, Map<String, Object> properties) {
       return sendMessageWithProperties(SimpleString.toSimpleString(address), properties);
    }
 
-   /**
-    * Create a new message with the specified body and properties, and send the message to an address
-    *
-    * @param address    the target queueName for the message
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessageWithProperties(String address, byte[] body, Map<String, Object> properties) {
       return sendMessageWithProperties(SimpleString.toSimpleString(address), body, properties);
    }
 
-   /**
-    * Create a new message with the specified body and properties, and send the message to an address
-    *
-    * @param address    the target queueName for the message
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessageWithProperties(String address, String body, Map<String, Object> properties) {
       return sendMessageWithProperties(SimpleString.toSimpleString(address), body, properties);
    }
 
-   /**
-    * Send a message to an queueName
-    *
-    * @param address the target queueName for the message
-    * @param message the message to send
-    */
+   @Override
    public void sendMessage(SimpleString address, ClientMessage message) {
       if (address == null) {
          throw new IllegalArgumentException("sendMessage failure - queueName is required");
@@ -570,67 +441,35 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       internalClient.sendMessage(address, message);
    }
 
-   /**
-    * Create a new message with the specified body, and send the message to an queueName
-    *
-    * @param address the target queueName for the message
-    * @param body    the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString address, byte[] body) {
       ClientMessage message = createMessage(body);
       sendMessage(address, message);
       return message;
    }
 
-   /**
-    * Create a new message with the specified body, and send the message to an queueName
-    *
-    * @param address the target queueName for the message
-    * @param body    the body for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessage(SimpleString address, String body) {
       ClientMessage message = createMessage(body);
       sendMessage(address, message);
       return message;
    }
 
-   /**
-    * Create a new message with the specified properties, and send the message to an queueName
-    *
-    * @param address    the target queueName for the message
-    * @param properties message properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessageWithProperties(SimpleString address, Map<String, Object> properties) {
       ClientMessage message = createMessageWithProperties(properties);
       sendMessage(address, message);
       return message;
    }
 
-   /**
-    * Create a new message with the specified body and properties, and send the message to an queueName
-    *
-    * @param address    the target queueName for the message
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessageWithProperties(SimpleString address, byte[] body, Map<String, Object> properties) {
       ClientMessage message = createMessageWithProperties(body, properties);
       sendMessage(address, message);
       return message;
    }
 
-   /**
-    * Create a new message with the specified body and properties, and send the message to an queueName
-    *
-    * @param address    the target queueName for the message
-    * @param body       the body for the new message
-    * @param properties message properties for the new message
-    * @return the message that was sent
-    */
+   @Override
    public ClientMessage sendMessageWithProperties(SimpleString address, String body, Map<String, Object> properties) {
 
       ClientMessage message = createMessageWithProperties(body, properties);
@@ -638,89 +477,45 @@ public class EmbeddedActiveMQResource extends ExternalResource {
       return message;
    }
 
-   /**
-    * Receive a message from the specified queue using the default receive timeout
-    *
-    * @param queueName name of the source queue
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage receiveMessage(String queueName) {
       return receiveMessage(SimpleString.toSimpleString(queueName));
    }
 
-   /**
-    * Receive a message from the specified queue using the specified receive timeout
-    *
-    * @param queueName name of the source queue
-    * @param timeout   receive timeout in milliseconds
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage receiveMessage(String queueName, long timeout) {
       return receiveMessage(SimpleString.toSimpleString(queueName), timeout);
    }
 
-   /**
-    * Receive a message from the specified queue using the default receive timeout
-    *
-    * @param queueName name of the source queue
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage receiveMessage(SimpleString queueName) {
       final boolean browseOnly = false;
       return getInternalClient().receiveMessage(queueName, defaultReceiveTimeout, browseOnly);
    }
 
-   /**
-    * Receive a message from the specified queue using the specified receive timeout
-    *
-    * @param queueName name of the source queue
-    * @param timeout   receive timeout in milliseconds
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage receiveMessage(SimpleString queueName, long timeout) {
       final boolean browseOnly = false;
       return getInternalClient().receiveMessage(queueName, timeout, browseOnly);
    }
 
-   /**
-    * Browse a message (receive but do not consume) from the specified queue using the default receive timeout
-    *
-    * @param queueName name of the source queue
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage browseMessage(String queueName) {
       return browseMessage(SimpleString.toSimpleString(queueName), defaultReceiveTimeout);
    }
 
-   /**
-    * Browse a message (receive but do not consume) a message from the specified queue using the specified receive timeout
-    *
-    * @param queueName name of the source queue
-    * @param timeout   receive timeout in milliseconds
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage browseMessage(String queueName, long timeout) {
       return browseMessage(SimpleString.toSimpleString(queueName), timeout);
    }
 
-   /**
-    * Browse a message (receive but do not consume) from the specified queue using the default receive timeout
-    *
-    * @param queueName name of the source queue
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage browseMessage(SimpleString queueName) {
       final boolean browseOnly = true;
       return getInternalClient().receiveMessage(queueName, defaultReceiveTimeout, browseOnly);
    }
 
-   /**
-    * Browse a message (receive but do not consume) a message from the specified queue using the specified receive timeout
-    *
-    * @param queueName name of the source queue
-    * @param timeout   receive timeout in milliseconds
-    * @return the received ClientMessage, null if the receive timed-out
-    */
+   @Override
    public ClientMessage browseMessage(SimpleString queueName, long timeout) {
       final boolean browseOnly = true;
       return getInternalClient().receiveMessage(queueName, timeout, browseOnly);
@@ -822,7 +617,9 @@ public class EmbeddedActiveMQResource extends ExternalResource {
          try {
             producer.send(address, message);
          } catch (ActiveMQException amqEx) {
-            throw new EmbeddedActiveMQResourceException(String.format("Failed to send message to %s", address.toString()), amqEx);
+            throw new EmbeddedActiveMQResourceException(String.format("Failed to send message to %s",
+                                                                      address.toString()),
+                                                        amqEx);
          }
       }
 
@@ -833,7 +630,9 @@ public class EmbeddedActiveMQResource extends ExternalResource {
          try {
             consumer = session.createConsumer(address, browseOnly);
          } catch (ActiveMQException amqEx) {
-            throw new EmbeddedActiveMQResourceException(String.format("Failed to create consumer for %s", address.toString()), amqEx);
+            throw new EmbeddedActiveMQResourceException(String.format("Failed to create consumer for %s",
+                                                                      address.toString()),
+                                                        amqEx);
          }
 
          ClientMessage message = null;
@@ -841,19 +640,25 @@ public class EmbeddedActiveMQResource extends ExternalResource {
             try {
                message = consumer.receive(timeout);
             } catch (ActiveMQException amqEx) {
-               throw new EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive( timeout = %d ) for %s failed", timeout, address.toString()), amqEx);
+               throw new EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive( timeout = %d ) for %s failed",
+                                                                         timeout, address.toString()),
+                                                           amqEx);
             }
          } else if (timeout == 0) {
             try {
                message = consumer.receiveImmediate();
             } catch (ActiveMQException amqEx) {
-               throw new EmbeddedActiveMQResourceException(String.format("ClientConsumer.receiveImmediate() for %s failed", address.toString()), amqEx);
+               throw new EmbeddedActiveMQResourceException(String.format("ClientConsumer.receiveImmediate() for %s failed",
+                                                                         address.toString()),
+                                                           amqEx);
             }
          } else {
             try {
                message = consumer.receive();
             } catch (ActiveMQException amqEx) {
-               throw new EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive() for %s failed", address.toString()), amqEx);
+               throw new EmbeddedActiveMQResourceException(String.format("ClientConsumer.receive() for %s failed",
+                                                                         address.toString()),
+                                                           amqEx);
             }
          }
 
diff --git a/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQOperations.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQOperations.java
new file mode 100644
index 0000000000..82ca3d36f5
--- /dev/null
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedActiveMQOperations.java
@@ -0,0 +1,348 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.api.core.client.ClientMessage;
+import org.apache.activemq.artemis.core.server.Queue;
+import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
+
+public interface EmbeddedActiveMQOperations {
+
+   /**
+    * Start the embedded ActiveMQ Artemis server. The server will normally be started by JUnit using
+    * the before() method. This method allows the server to be started manually to support advanced
+    * testing scenarios.
+    */
+   void start();
+
+   /**
+    * Stop the embedded ActiveMQ Artemis server The server will normally be stopped by JUnit using
+    * the after() method. This method allows the server to be stopped manually to support advanced
+    * testing scenarios.
+    */
+   void stop();
+
+   boolean isUseDurableMessage();
+
+   /**
+    * Disables/Enables creating durable messages. By default, durable messages are created
+    * @param useDurableMessage if true, durable messages will be created
+    */
+   void setUseDurableMessage(boolean useDurableMessage);
+
+   boolean isUseDurableQueue();
+
+   /**
+    * Disables/Enables creating durable queues. By default, durable queues are created
+    * @param useDurableQueue if true, durable messages will be created
+    */
+   void setUseDurableQueue(boolean useDurableQueue);
+
+   long getDefaultReceiveTimeout();
+
+   /**
+    * Sets the default timeout in milliseconds used when receiving messages. Defaults to 50
+    * milliseconds
+    * @param defaultReceiveTimeout received timeout in milliseconds
+    */
+   void setDefaultReceiveTimeout(long defaultReceiveTimeout);
+
+   /**
+    * Get the EmbeddedActiveMQ server. This may be required for advanced configuration of the
+    * EmbeddedActiveMQ server.
+    * @return the embedded ActiveMQ broker
+    */
+   EmbeddedActiveMQ getServer();
+
+   /**
+    * Get the name of the EmbeddedActiveMQ server
+    * @return name of the embedded server
+    */
+   String getServerName();
+
+   /**
+    * Get the VM URL for the embedded EmbeddedActiveMQ server
+    * @return the VM URL for the embedded server
+    */
+   String getVmURL();
+
+   /**
+    * Get the number of messages in a specific queue.
+    * @param queueName the name of the queue
+    * @return the number of messages in the queue; -1 if queue is not found
+    */
+   long getMessageCount(String queueName);
+
+   /**
+    * Get the number of messages in a specific queue.
+    * @param queueName the name of the queue
+    * @return the number of messages in the queue; -1 if queue is not found
+    */
+   long getMessageCount(SimpleString queueName);
+
+   Queue locateQueue(String queueName);
+
+   Queue locateQueue(SimpleString queueName);
+
+   List<Queue> getBoundQueues(String address);
+
+   List<Queue> getBoundQueues(SimpleString address);
+
+   Queue createQueue(String name);
+
+   Queue createQueue(String address, String name);
+
+   Queue createQueue(SimpleString address, SimpleString name);
+
+   void createSharedQueue(String name, String user);
+
+   void createSharedQueue(String address, String name, String user);
+
+   void createSharedQueue(SimpleString address, SimpleString name, SimpleString user);
+
+   /**
+    * Create a ClientMessage.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @return a new ClientMessage
+    */
+   ClientMessage createMessage();
+
+   /**
+    * Create a ClientMessage with the specified body.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @return a new ClientMessage with the specified body
+    */
+   ClientMessage createMessage(byte[] body);
+
+   /**
+    * Create a ClientMessage with the specified body.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @return a new ClientMessage with the specified body
+    */
+   ClientMessage createMessage(String body);
+
+   /**
+    * Create a ClientMessage with the specified message properties.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param properties message properties for the new message
+    * @return a new ClientMessage with the specified message properties
+    */
+   ClientMessage createMessageWithProperties(Map<String, Object> properties);
+
+   /**
+    * Create a ClientMessage with the specified body and message properties.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return a new ClientMessage with the specified body and message properties
+    */
+   ClientMessage createMessageWithProperties(byte[] body, Map<String, Object> properties);
+
+   /**
+    * Create a ClientMessage with the specified body and message properties.
+    * <p>
+    * If useDurableMessage is false, a non-durable message is created. Otherwise, a durable message
+    * is created.
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return a new ClientMessage with the specified body and message properties
+    */
+   ClientMessage createMessageWithProperties(String body, Map<String, Object> properties);
+
+   /**
+    * Send a message to an address
+    * @param address the target queueName for the message
+    * @param message the message to send
+    */
+   void sendMessage(String address, ClientMessage message);
+
+   /**
+    * Create a new message with the specified body, and send the message to an address
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(String address, byte[] body);
+
+   /**
+    * Create a new message with the specified body, and send the message to an address
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(String address, String body);
+
+   /**
+    * Create a new message with the specified properties, and send the message to an address
+    * @param address the target queueName for the message
+    * @param properties message properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessageWithProperties(String address, Map<String, Object> properties);
+
+   /**
+    * Create a new message with the specified body and properties, and send the message to an
+    * address
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessageWithProperties(String address, byte[] body, Map<String, Object> properties);
+
+   /**
+    * Create a new message with the specified body and properties, and send the message to an
+    * address
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessageWithProperties(String address, String body, Map<String, Object> properties);
+
+   /**
+    * Send a message to an queueName
+    * @param address the target queueName for the message
+    * @param message the message to send
+    */
+   void sendMessage(SimpleString address, ClientMessage message);
+
+   /**
+    * Create a new message with the specified body, and send the message to an queueName
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString address, byte[] body);
+
+   /**
+    * Create a new message with the specified body, and send the message to an queueName
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessage(SimpleString address, String body);
+
+   /**
+    * Create a new message with the specified properties, and send the message to an queueName
+    * @param address the target queueName for the message
+    * @param properties message properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessageWithProperties(SimpleString address, Map<String, Object> properties);
+
+   /**
+    * Create a new message with the specified body and properties, and send the message to an
+    * queueName
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessageWithProperties(SimpleString address, byte[] body, Map<String, Object> properties);
+
+   /**
+    * Create a new message with the specified body and properties, and send the message to an
+    * queueName
+    * @param address the target queueName for the message
+    * @param body the body for the new message
+    * @param properties message properties for the new message
+    * @return the message that was sent
+    */
+   ClientMessage sendMessageWithProperties(SimpleString address, String body, Map<String, Object> properties);
+
+   /**
+    * Receive a message from the specified queue using the default receive timeout
+    * @param queueName name of the source queue
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage receiveMessage(String queueName);
+
+   /**
+    * Receive a message from the specified queue using the specified receive timeout
+    * @param queueName name of the source queue
+    * @param timeout receive timeout in milliseconds
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage receiveMessage(String queueName, long timeout);
+
+   /**
+    * Receive a message from the specified queue using the default receive timeout
+    * @param queueName name of the source queue
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage receiveMessage(SimpleString queueName);
+
+   /**
+    * Receive a message from the specified queue using the specified receive timeout
+    * @param queueName name of the source queue
+    * @param timeout receive timeout in milliseconds
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage receiveMessage(SimpleString queueName, long timeout);
+
+   /**
+    * Browse a message (receive but do not consume) from the specified queue using the default
+    * receive timeout
+    * @param queueName name of the source queue
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage browseMessage(String queueName);
+
+   /**
+    * Browse a message (receive but do not consume) a message from the specified queue using the
+    * specified receive timeout
+    * @param queueName name of the source queue
+    * @param timeout receive timeout in milliseconds
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage browseMessage(String queueName, long timeout);
+
+   /**
+    * Browse a message (receive but do not consume) from the specified queue using the default
+    * receive timeout
+    * @param queueName name of the source queue
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage browseMessage(SimpleString queueName);
+
+   /**
+    * Browse a message (receive but do not consume) a message from the specified queue using the
+    * specified receive timeout
+    * @param queueName name of the source queue
+    * @param timeout receive timeout in milliseconds
+    * @return the received ClientMessage, null if the receive timed-out
+    */
+   ClientMessage browseMessage(SimpleString queueName, long timeout);
+
+}
\ No newline at end of file
diff --git a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSResource.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSDelegate.java
similarity index 73%
rename from artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSResource.java
rename to artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSDelegate.java
index acd98b87f4..89429370fb 100644
--- a/artemis-junit/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSResource.java
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSDelegate.java
@@ -16,6 +16,13 @@
  */
 package org.apache.activemq.artemis.junit;
 
+import java.io.Serializable;
+import java.lang.invoke.MethodHandles;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
 import javax.jms.BytesMessage;
 import javax.jms.Connection;
 import javax.jms.ConnectionFactory;
@@ -27,11 +34,6 @@ import javax.jms.ObjectMessage;
 import javax.jms.Session;
 import javax.jms.StreamMessage;
 import javax.jms.TextMessage;
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
 
 import org.apache.activemq.artemis.api.core.SimpleString;
 import org.apache.activemq.artemis.api.core.TransportConfiguration;
@@ -51,37 +53,21 @@ import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
 import org.apache.activemq.artemis.jms.server.config.impl.FileJMSConfiguration;
 import org.apache.activemq.artemis.jms.server.config.impl.JMSConfigurationImpl;
 import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
-import org.junit.rules.ExternalResource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Deprecated in favor of EmbeddedActiveMQResource. Since Artemis 2.0 all JMS specific broker management classes,
- * interfaces, and methods have been deprecated in favor of their more general counter-parts.
- *
- * A JUnit Rule that embeds an ActiveMQ Artemis JMS server into a test.
- *
- * This JUnit Rule is designed to simplify using embedded servers in unit tests.  Adding the rule to a test will startup
- * an embedded JMS server, which can then be used by client applications.
- *
- * <pre><code>
- * public class SimpleTest {
- *     &#64;Rule
- *     public EmbeddedJMSResource server = new EmbeddedJMSResource();
- *
- *     &#64;Test
- *     public void testSomething() throws Exception {
- *         // Use the embedded server here
- *     }
- * }
- * </code></pre>
+ * Deprecated in favor of EmbeddedActiveMQDelegate. Since Artemis 2.0 all JMS specific broker
+ * management classes, interfaces, and methods have been deprecated in favor of their more general
+ * counter-parts.
+ * @see EmbeddedActiveMQDelegate
  */
 @Deprecated
-public class EmbeddedJMSResource extends ExternalResource {
+public class EmbeddedJMSDelegate implements EmbeddedJMSOperations<EmbeddedJMSDelegate> {
 
    static final String SERVER_NAME = "embedded-jms-server";
 
-   Logger log = LoggerFactory.getLogger(this.getClass());
+   private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    Integer serverId = null;
 
    Configuration configuration;
@@ -93,16 +79,19 @@ public class EmbeddedJMSResource extends ExternalResource {
    /**
     * Create a default EmbeddedJMSResource
     */
-   public EmbeddedJMSResource() {
+   protected EmbeddedJMSDelegate() {
       this(false);
    }
 
    /**
     * Create a default EmbeddedJMSResource
     */
-   public EmbeddedJMSResource(boolean useNetty) {
+   protected EmbeddedJMSDelegate(boolean useNetty) {
       try {
-         configuration = new ConfigurationImpl().setName(SERVER_NAME).setPersistenceEnabled(false).setSecurityEnabled(false).addAcceptorConfiguration("invm", "vm://0");
+         configuration = new ConfigurationImpl().setName(SERVER_NAME)
+                                                .setPersistenceEnabled(false)
+                                                .setSecurityEnabled(false)
+                                                .addAcceptorConfiguration("invm", "vm://0");
 
          if (useNetty) {
             configuration.addAcceptorConfiguration("netty", DefaultConnectionProperties.DEFAULT_BROKER_BIND_URL);
@@ -119,7 +108,8 @@ public class EmbeddedJMSResource extends ExternalResource {
    /**
     * The acceptor used
     */
-   public EmbeddedJMSResource addAcceptor(String name, String uri) throws Exception {
+   @Override
+   public EmbeddedJMSDelegate addAcceptor(String name, String uri) throws Exception {
       configuration.addAcceptorConfiguration(name, uri);
       return this;
    }
@@ -127,12 +117,17 @@ public class EmbeddedJMSResource extends ExternalResource {
    /**
     * Create a default EmbeddedJMSResource with the specified server id
     */
-   public EmbeddedJMSResource(int serverId) {
+   protected EmbeddedJMSDelegate(int serverId) {
       this.serverId = serverId;
       Map<String, Object> props = new HashMap<>();
       props.put(TransportConstants.SERVER_ID_PROP_NAME, serverId);
 
-      configuration = new ConfigurationImpl().setName(SERVER_NAME + "-" + serverId).setPersistenceEnabled(false).setSecurityEnabled(false).addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName(), props));
+      configuration =
+               new ConfigurationImpl().setName(SERVER_NAME + "-" + serverId)
+                                      .setPersistenceEnabled(false)
+                                      .setSecurityEnabled(false)
+                                      .addAcceptorConfiguration(new TransportConfiguration(InVMAcceptorFactory.class.getName(),
+                                                                                           props));
 
       jmsConfiguration = new JMSConfigurationImpl();
 
@@ -141,11 +136,10 @@ public class EmbeddedJMSResource extends ExternalResource {
 
    /**
     * Create an EmbeddedJMSResource with the specified configurations
-    *
-    * @param configuration    ActiveMQServer configuration
+    * @param configuration ActiveMQServer configuration
     * @param jmsConfiguration JMSServerManager configuration
     */
-   public EmbeddedJMSResource(Configuration configuration, JMSConfiguration jmsConfiguration) {
+   protected EmbeddedJMSDelegate(Configuration configuration, JMSConfiguration jmsConfiguration) {
       this.configuration = configuration;
       this.jmsConfiguration = jmsConfiguration;
       init();
@@ -153,20 +147,18 @@ public class EmbeddedJMSResource extends ExternalResource {
 
    /**
     * Create an EmbeddedJMSResource with the specified configuration file
-    *
     * @param filename configuration file name
     */
-   public EmbeddedJMSResource(String filename) {
+   protected EmbeddedJMSDelegate(String filename) {
       this(filename, filename);
    }
 
    /**
     * Create an EmbeddedJMSResource with the specified configuration file
-    *
     * @param serverConfigurationFileName ActiveMQServer configuration file name
-    * @param jmsConfigurationFileName    JMSServerManager configuration file name
+    * @param jmsConfigurationFileName JMSServerManager configuration file name
     */
-   public EmbeddedJMSResource(String serverConfigurationFileName, String jmsConfigurationFileName) {
+   protected EmbeddedJMSDelegate(String serverConfigurationFileName, String jmsConfigurationFileName) {
       if (serverConfigurationFileName == null) {
          throw new IllegalArgumentException("ActiveMQServer configuration file name cannot be null");
       }
@@ -180,7 +172,9 @@ public class EmbeddedJMSResource extends ExternalResource {
       try {
          coreDeploymentManager.readConfiguration();
       } catch (Exception readCoreConfigEx) {
-         throw new EmbeddedJMSResourceException(String.format("Failed to read ActiveMQServer configuration from file %s", serverConfigurationFileName), readCoreConfigEx);
+         throw new EmbeddedJMSResourceException(String.format("Failed to read ActiveMQServer configuration from file %s",
+                                                              serverConfigurationFileName),
+                                                readCoreConfigEx);
       }
       this.configuration = coreConfiguration;
 
@@ -190,7 +184,9 @@ public class EmbeddedJMSResource extends ExternalResource {
       try {
          jmsDeploymentManager.readConfiguration();
       } catch (Exception readJmsConfigEx) {
-         throw new EmbeddedJMSResourceException(String.format("Failed to read JMSServerManager configuration from file %s", jmsConfigurationFileName), readJmsConfigEx);
+         throw new EmbeddedJMSResourceException(String.format("Failed to read JMSServerManager configuration from file %s",
+                                                              jmsConfigurationFileName),
+                                                readJmsConfigEx);
       }
       this.jmsConfiguration = jmsConfiguration;
 
@@ -203,7 +199,9 @@ public class EmbeddedJMSResource extends ExternalResource {
             try {
                message.setObjectProperty(property.getKey(), property.getValue());
             } catch (JMSException jmsEx) {
-               throw new EmbeddedJMSResourceException(String.format("Failed to set property {%s = %s}", property.getKey(), property.getValue().toString()), jmsEx);
+               throw new EmbeddedJMSResourceException(String.format("Failed to set property {%s = %s}",
+                                                                    property.getKey(), property.getValue().toString()),
+                                                      jmsEx);
             }
          }
       }
@@ -218,30 +216,34 @@ public class EmbeddedJMSResource extends ExternalResource {
    /**
     * Start the embedded EmbeddedJMSResource.
     * <p>
-    * The server will normally be started by JUnit using the before() method.  This method allows the server to
-    * be started manually to support advanced testing scenarios.
+    * The server will normally be started by JUnit using the before() method. This method allows the
+    * server to be started manually to support advanced testing scenarios.
     */
+   @Override
    public void start() {
-      log.info("Starting {}: {}", this.getClass().getSimpleName(), this.getServerName());
+      logger.info("Starting {}: {}", this.getClass().getSimpleName(), this.getServerName());
       try {
          jmsServer.start();
       } catch (Exception ex) {
-         throw new RuntimeException(String.format("Exception encountered starting %s: %s", jmsServer.getClass().getSimpleName(), this.getServerName()), ex);
+         throw new RuntimeException(String.format("Exception encountered starting %s: %s",
+                                                  jmsServer.getClass().getSimpleName(), this.getServerName()),
+                                    ex);
       }
    }
 
    /**
     * Stop the embedded ActiveMQ broker, blocking until the broker has stopped.
     * <p>
-    * The broker will normally be stopped by JUnit using the after() method.  This method allows the broker to
-    * be stopped manually to support advanced testing scenarios.
+    * The broker will normally be stopped by JUnit using the after() method. This method allows the
+    * broker to be stopped manually to support advanced testing scenarios.
     */
+   @Override
    public void stop() {
       String name = "null";
       if (jmsServer != null) {
          name = this.getServerName();
       }
-      log.info("Stopping {}: {}", this.getClass().getSimpleName(), name);
+      logger.info("Stopping {}: {}", this.getClass().getSimpleName(), name);
       if (internalClient != null) {
          internalClient.stop();
          internalClient = null;
@@ -251,55 +253,19 @@ public class EmbeddedJMSResource extends ExternalResource {
          try {
             jmsServer.stop();
          } catch (Exception ex) {
-            log.warn(String.format("Exception encountered stopping %s: %s - ignoring", jmsServer.getClass().getSimpleName(), this.getServerName()), ex);
+            logger.warn(String.format("Exception encountered stopping %s: %s - ignoring",
+                                      jmsServer.getClass().getSimpleName(), this.getServerName()),
+                        ex);
          }
       }
    }
 
-   /**
-    * Start the embedded ActiveMQ Broker
-    * <p>
-    * Invoked by JUnit to setup the resource
-    */
    @Override
-   protected void before() throws Throwable {
-      log.info("Starting {}: {}", this.getClass().getSimpleName(), getServerName());
-
-      this.start();
-
-      super.before();
-   }
-
-   /**
-    * Stop the embedded ActiveMQ Broker
-    * <p>
-    * Invoked by JUnit to tear down the resource
-    */
-   @Override
-   protected void after() {
-      log.info("Stopping {}: {}", this.getClass().getSimpleName(), getServerName());
-
-      super.after();
-
-      this.stop();
-   }
-
-   /**
-    * Get the EmbeddedJMS server.
-    * <p>
-    * This may be required for advanced configuration of the EmbeddedJMS server.
-    *
-    * @return
-    */
    public EmbeddedJMS getJmsServer() {
       return jmsServer;
    }
 
-   /**
-    * Get the name of the EmbeddedJMS server
-    *
-    * @return name of the server
-    */
+   @Override
    public String getServerName() {
       String name = "unknown";
       ActiveMQServer activeMQServer = jmsServer.getActiveMQServer();
@@ -312,11 +278,7 @@ public class EmbeddedJMSResource extends ExternalResource {
       return name;
    }
 
-   /**
-    * Get the VM URL for the embedded EmbeddedActiveMQ server
-    *
-    * @return the VM URL for the embedded server
-    */
+   @Override
    public String getVmURL() {
       String vmURL = "vm://0";
       for (TransportConfiguration transportConfiguration : configuration.getAcceptorConfigurations()) {
@@ -329,21 +291,11 @@ public class EmbeddedJMSResource extends ExternalResource {
       return vmURL;
    }
 
-   /**
-    * Get the Queue corresponding to a JMS Destination.
-    * <p>
-    * The full name of the JMS destination including the prefix should be provided - i.e. queue://myQueue
-    * or topic://myTopic.  If the destination type prefix is not included in the destination name, a prefix
-    * of "queue://" is assumed.
-    *
-    * @param destinationName the full name of the JMS Destination
-    * @return the number of messages in the JMS Destination
-    */
+   @Override
    public Queue getDestinationQueue(String destinationName) {
       Queue queue = null;
-      ActiveMQDestination destination = ActiveMQDestination.createDestination(destinationName, ActiveMQDestination.TYPE.QUEUE);
-      String address = destination.getAddress();
-      String name = destination.getName();
+      ActiveMQDestination destination =
+               ActiveMQDestination.createDestination(destinationName, ActiveMQDestination.TYPE.QUEUE);
       if (destination.isQueue()) {
          queue = jmsServer.getActiveMQServer().locateQueue(destination.getSimpleAddress());
       } else {
@@ -351,7 +303,9 @@ public class EmbeddedJMSResource extends ExternalResource {
          try {
             bindingQueryResult = jmsServer.getActiveMQServer().bindingQuery(destination.getSimpleAddress());
          } catch (Exception ex) {
-            log.error(String.format("getDestinationQueue( %s ) - bindingQuery for %s failed", destinationName, destination.getAddress()), ex);
+            logger.error(String.format("getDestinationQueue( %s ) - bindingQuery for %s failed", destinationName,
+                                       destination.getAddress()),
+                         ex);
             return null;
          }
          if (bindingQueryResult.isExists()) {
@@ -365,24 +319,19 @@ public class EmbeddedJMSResource extends ExternalResource {
       return queue;
    }
 
-   /**
-    * Get the Queues corresponding to a JMS Topic.
-    * <p>
-    * The full name of the JMS Topic including the prefix should be provided - i.e. topic://myTopic.  If the destination type prefix
-    * is not included in the destination name, a prefix of "topic://" is assumed.
-    *
-    * @param topicName the full name of the JMS Destination
-    * @return the number of messages in the JMS Destination
-    */
+   @Override
    public List<Queue> getTopicQueues(String topicName) {
       List<Queue> queues = new LinkedList<>();
-      ActiveMQDestination destination = ActiveMQDestination.createDestination(topicName, ActiveMQDestination.TYPE.TOPIC);
+      ActiveMQDestination destination =
+               ActiveMQDestination.createDestination(topicName, ActiveMQDestination.TYPE.TOPIC);
       if (!destination.isQueue()) {
          BindingQueryResult bindingQueryResult = null;
          try {
             bindingQueryResult = jmsServer.getActiveMQServer().bindingQuery(destination.getSimpleAddress());
          } catch (Exception ex) {
-            log.error(String.format("getTopicQueues( %s ) - bindingQuery for %s failed", topicName, destination.getAddress()), ex);
+            logger.error(String.format("getTopicQueues( %s ) - bindingQuery for %s failed", topicName,
+                                       destination.getAddress()),
+                         ex);
             return queues;
          }
 
@@ -397,27 +346,15 @@ public class EmbeddedJMSResource extends ExternalResource {
       return queues;
    }
 
-   /**
-    * Get the number of messages in a specific JMS Destination.
-    * <p>
-    * The full name of the JMS destination including the prefix should be provided - i.e. queue://myQueue
-    * or topic://myTopic.  If the destination type prefix is not included in the destination name, a prefix
-    * of "queue://" is assumed.
-    *
-    * NOTE:  For JMS Topics, this returned count will be the total number of messages for all subscribers.  For
-    * example, if there are two subscribers on the topic and a single message is published, the returned count will
-    * be two (one message for each subscriber).
-    *
-    * @param destinationName the full name of the JMS Destination
-    * @return the number of messages in the JMS Destination
-    */
+   @Override
    public long getMessageCount(String destinationName) {
       long count = 0;
-      ActiveMQDestination destination = ActiveMQDestination.createDestination(destinationName, ActiveMQDestination.TYPE.QUEUE);
+      ActiveMQDestination destination =
+               ActiveMQDestination.createDestination(destinationName, ActiveMQDestination.TYPE.QUEUE);
       if (destination.isQueue()) {
          Queue queue = getDestinationQueue(destinationName);
          if (queue == null) {
-            log.warn("getMessageCount(destinationName) - destination {} not found; returning -1", destinationName);
+            logger.warn("getMessageCount(destinationName) - destination {} not found; returning -1", destinationName);
             count = -1;
          } else {
             count = queue.getMessageCount();
@@ -431,49 +368,61 @@ public class EmbeddedJMSResource extends ExternalResource {
       return count;
    }
 
+   @Override
    public BytesMessage createBytesMessage() {
       return getInternalClient().createBytesMessage();
    }
 
+   @Override
    public TextMessage createTextMessage() {
       return getInternalClient().createTextMessage();
    }
 
+   @Override
    public MapMessage createMapMessage() {
       return getInternalClient().createMapMessage();
    }
 
+   @Override
    public ObjectMessage createObjectMessage() {
       return getInternalClient().createObjectMessage();
    }
 
+   @Override
    public StreamMessage createStreamMessage() {
       return getInternalClient().createStreamMessage();
    }
 
+   @Override
    public BytesMessage createMessage(byte[] body) {
       return createMessage(body, null);
    }
 
+   @Override
    public TextMessage createMessage(String body) {
       return createMessage(body, null);
    }
 
+   @Override
    public MapMessage createMessage(Map<String, Object> body) {
       return createMessage(body, null);
    }
 
+   @Override
    public ObjectMessage createMessage(Serializable body) {
       return createMessage(body, null);
    }
 
+   @Override
    public BytesMessage createMessage(byte[] body, Map<String, Object> properties) {
       BytesMessage message = this.createBytesMessage();
       if (body != null) {
          try {
             message.writeBytes(body);
          } catch (JMSException jmsEx) {
-            throw new EmbeddedJMSResourceException(String.format("Failed to set body {%s} on BytesMessage", new String(body)), jmsEx);
+            throw new EmbeddedJMSResourceException(String.format("Failed to set body {%s} on BytesMessage",
+                                                                 new String(body)),
+                                                   jmsEx);
          }
       }
 
@@ -482,13 +431,15 @@ public class EmbeddedJMSResource extends ExternalResource {
       return message;
    }
 
+   @Override
    public TextMessage createMessage(String body, Map<String, Object> properties) {
       TextMessage message = this.createTextMessage();
       if (body != null) {
          try {
             message.setText(body);
          } catch (JMSException jmsEx) {
-            throw new EmbeddedJMSResourceException(String.format("Failed to set body {%s} on TextMessage", body), jmsEx);
+            throw new EmbeddedJMSResourceException(String.format("Failed to set body {%s} on TextMessage", body),
+                                                   jmsEx);
          }
       }
 
@@ -497,6 +448,7 @@ public class EmbeddedJMSResource extends ExternalResource {
       return message;
    }
 
+   @Override
    public MapMessage createMessage(Map<String, Object> body, Map<String, Object> properties) {
       MapMessage message = this.createMapMessage();
 
@@ -505,7 +457,9 @@ public class EmbeddedJMSResource extends ExternalResource {
             try {
                message.setObject(entry.getKey(), entry.getValue());
             } catch (JMSException jmsEx) {
-               throw new EmbeddedJMSResourceException(String.format("Failed to set body entry {%s = %s} on MapMessage", entry.getKey(), entry.getValue().toString()), jmsEx);
+               throw new EmbeddedJMSResourceException(String.format("Failed to set body entry {%s = %s} on MapMessage",
+                                                                    entry.getKey(), entry.getValue().toString()),
+                                                      jmsEx);
             }
          }
       }
@@ -515,6 +469,7 @@ public class EmbeddedJMSResource extends ExternalResource {
       return message;
    }
 
+   @Override
    public ObjectMessage createMessage(Serializable body, Map<String, Object> properties) {
       ObjectMessage message = this.createObjectMessage();
 
@@ -522,7 +477,9 @@ public class EmbeddedJMSResource extends ExternalResource {
          try {
             message.setObject(body);
          } catch (JMSException jmsEx) {
-            throw new EmbeddedJMSResourceException(String.format("Failed to set body {%s} on ObjectMessage", body.toString()), jmsEx);
+            throw new EmbeddedJMSResourceException(String.format("Failed to set body {%s} on ObjectMessage",
+                                                                 body.toString()),
+                                                   jmsEx);
          }
       }
 
@@ -531,69 +488,78 @@ public class EmbeddedJMSResource extends ExternalResource {
       return message;
    }
 
+   @Override
    public void pushMessage(String destinationName, Message message) {
       if (destinationName == null) {
          throw new IllegalArgumentException("sendMessage failure - destination name is required");
       } else if (message == null) {
          throw new IllegalArgumentException("sendMessage failure - a Message is required");
       }
-      ActiveMQDestination destination = ActiveMQDestination.createDestination(destinationName, ActiveMQDestination.TYPE.QUEUE);
+      ActiveMQDestination destination =
+               ActiveMQDestination.createDestination(destinationName, ActiveMQDestination.TYPE.QUEUE);
 
       getInternalClient().pushMessage(destination, message);
    }
 
+   @Override
    public BytesMessage pushMessage(String destinationName, byte[] body) {
       BytesMessage message = createMessage(body, null);
       pushMessage(destinationName, message);
       return message;
    }
 
+   @Override
    public TextMessage pushMessage(String destinationName, String body) {
       TextMessage message = createMessage(body, null);
       pushMessage(destinationName, message);
       return message;
    }
 
+   @Override
    public MapMessage pushMessage(String destinationName, Map<String, Object> body) {
       MapMessage message = createMessage(body, null);
       pushMessage(destinationName, message);
       return message;
    }
 
+   @Override
    public ObjectMessage pushMessage(String destinationName, Serializable body) {
       ObjectMessage message = createMessage(body, null);
       pushMessage(destinationName, message);
       return message;
    }
 
+   @Override
    public BytesMessage pushMessageWithProperties(String destinationName, byte[] body, Map<String, Object> properties) {
       BytesMessage message = createMessage(body, properties);
       pushMessage(destinationName, message);
       return message;
    }
 
+   @Override
    public TextMessage pushMessageWithProperties(String destinationName, String body, Map<String, Object> properties) {
       TextMessage message = createMessage(body, properties);
       pushMessage(destinationName, message);
       return message;
    }
 
-   public MapMessage pushMessageWithProperties(String destinationName,
-                                               Map<String, Object> body,
+   @Override
+   public MapMessage pushMessageWithProperties(String destinationName, Map<String, Object> body,
                                                Map<String, Object> properties) {
       MapMessage message = createMessage(body, properties);
       pushMessage(destinationName, message);
       return message;
    }
 
-   public ObjectMessage pushMessageWithProperties(String destinationName,
-                                                  Serializable body,
+   @Override
+   public ObjectMessage pushMessageWithProperties(String destinationName, Serializable body,
                                                   Map<String, Object> properties) {
       ObjectMessage message = createMessage(body, properties);
       pushMessage(destinationName, message);
       return message;
    }
 
+   @Override
    public Message peekMessage(String destinationName) {
       if (null == jmsServer) {
          throw new NullPointerException("peekMessage failure  - BrokerService is null");
@@ -606,29 +572,34 @@ public class EmbeddedJMSResource extends ExternalResource {
       throw new UnsupportedOperationException("Not yet implemented");
    }
 
+   @Override
    public BytesMessage peekBytesMessage(String destinationName) {
       return (BytesMessage) peekMessage(destinationName);
    }
 
+   @Override
    public TextMessage peekTextMessage(String destinationName) {
       return (TextMessage) peekMessage(destinationName);
    }
 
+   @Override
    public MapMessage peekMapMessage(String destinationName) {
       return (MapMessage) peekMessage(destinationName);
    }
 
+   @Override
    public ObjectMessage peekObjectMessage(String destinationName) {
       return (ObjectMessage) peekMessage(destinationName);
    }
 
+   @Override
    public StreamMessage peekStreamMessage(String destinationName) {
       return (StreamMessage) peekMessage(destinationName);
    }
 
    private InternalClient getInternalClient() {
       if (internalClient == null) {
-         log.info("Creating InternalClient");
+         logger.info("Creating InternalClient");
          internalClient = new InternalClient();
          internalClient.start();
       }
@@ -673,7 +644,7 @@ public class EmbeddedJMSResource extends ExternalResource {
          try {
             producer.close();
          } catch (JMSException jmsEx) {
-            log.warn("JMSException encounter closing InternalClient Session - MessageProducer", jmsEx);
+            logger.warn("JMSException encounter closing InternalClient Session - MessageProducer", jmsEx);
          } finally {
             producer = null;
          }
@@ -681,7 +652,7 @@ public class EmbeddedJMSResource extends ExternalResource {
          try {
             session.close();
          } catch (JMSException jmsEx) {
-            log.warn("JMSException encounter closing InternalClient Session - ignoring", jmsEx);
+            logger.warn("JMSException encounter closing InternalClient Session - ignoring", jmsEx);
          } finally {
             session = null;
          }
@@ -690,7 +661,7 @@ public class EmbeddedJMSResource extends ExternalResource {
             try {
                connection.close();
             } catch (JMSException jmsEx) {
-               log.warn("JMSException encounter closing InternalClient Connection - ignoring", jmsEx);
+               logger.warn("JMSException encounter closing InternalClient Connection - ignoring", jmsEx);
             } finally {
                connection = null;
             }
@@ -754,7 +725,10 @@ public class EmbeddedJMSResource extends ExternalResource {
          try {
             producer.send(destination, message);
          } catch (JMSException jmsEx) {
-            throw new EmbeddedJMSResourceException(String.format("Failed to push %s to %s", message.getClass().getSimpleName(), destination.toString()), jmsEx);
+            throw new EmbeddedJMSResourceException(String.format("Failed to push %s to %s",
+                                                                 message.getClass().getSimpleName(),
+                                                                 destination.toString()),
+                                                   jmsEx);
          }
       }
 
diff --git a/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSOperations.java b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSOperations.java
new file mode 100644
index 0000000000..e0e2e0c1f6
--- /dev/null
+++ b/artemis-junit/artemis-junit-commons/src/main/java/org/apache/activemq/artemis/junit/EmbeddedJMSOperations.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.junit;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import javax.jms.BytesMessage;
+import javax.jms.MapMessage;
+import javax.jms.Message;
+import javax.jms.ObjectMessage;
+import javax.jms.StreamMessage;
+import javax.jms.TextMessage;
+
+import org.apache.activemq.artemis.core.server.Queue;
+import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
+
+/**
+ * Deprecated in favor of EmbeddedActiveMQDelegate. Since Artemis 2.0 all JMS specific broker
+ * management classes, interfaces, and methods have been deprecated in favor of their more general
+ * counter-parts.
+ * @param <I> implementing type
+ * @see EmbeddedActiveMQDelegate
+ */
+@Deprecated
+public interface EmbeddedJMSOperations<I> {
+
+   /**
+    * The acceptor used
+    */
+   I addAcceptor(String name, String uri) throws Exception;
+
+   /**
+    * Start the embedded EmbeddedJMSResource.
+    * <p>
+    * The server will normally be started by JUnit using the before() method. This method allows the
+    * server to be started manually to support advanced testing scenarios.
+    */
+   void start();
+
+   /**
+    * Stop the embedded ActiveMQ broker, blocking until the broker has stopped.
+    * <p>
+    * The broker will normally be stopped by JUnit using the after() method. This method allows the
+    * broker to be stopped manually to support advanced testing scenarios.
+    */
+   void stop();
+
+   /**
+    * Get the EmbeddedJMS server.
+    * <p>
+    * This may be required for advanced configuration of the EmbeddedJMS server.
+    * @return
+    */
+   EmbeddedJMS getJmsServer();
+
+   /**
+    * Get the name of the EmbeddedJMS server
+    * @return name of the server
+    */
+   String getServerName();
+
+   /**
+    * Get the VM URL for the embedded EmbeddedActiveMQ server
+    * @return the VM URL for the embedded server
+    */
+   String getVmURL();
+
+   /**
+    * Get the Queue corresponding to a JMS Destination.
+    * <p>
+    * The full name of the JMS destination including the prefix should be provided - i.e.
+    * queue://myQueue or topic://myTopic. If the destination type prefix is not included in the
+    * destination name, a prefix of "queue://" is assumed.
+    * @param destinationName the full name of the JMS Destination
+    * @return the number of messages in the JMS Destination
+    */
+   Queue getDestinationQueue(String destinationName);
+
+   /**
+    * Get the Queues corresponding to a JMS Topic.
+    * <p>
+    * The full name of the JMS Topic including the prefix should be provided - i.e. topic://myTopic.
+    * If the destination type prefix is not included in the destination name, a prefix of "topic://"
+    * is assumed.
+    * @param topicName the full name of the JMS Destination
+    * @return the number of messages in the JMS Destination
+    */
+   List<Queue> getTopicQueues(String topicName);
+
+   /**
+    * Get the number of messages in a specific JMS Destination.
+    * <p>
+    * The full name of the JMS destination including the prefix should be provided - i.e.
+    * queue://myQueue or topic://myTopic. If the destination type prefix is not included in the
+    * destination name, a prefix of "queue://" is assumed. NOTE: For JMS Topics, this returned count
+    * will be the total number of messages for all subscribers. For example, if there are two
+    * subscribers on the topic and a single message is published, the returned count will be two
+    * (one message for each subscriber).
+    * @param destinationName the full name of the JMS Destination
+    * @return the number of messages in the JMS Destination
+    */
+   long getMessageCount(String destinationName);
+
+   BytesMessage createBytesMessage();
+
+   TextMessage createTextMessage();
+
+   MapMessage createMapMessage();
+
+   ObjectMessage createObjectMessage();
+
+   StreamMessage createStreamMessage();
+
+   BytesMessage createMessage(byte[] body);
+
+   TextMessage createMessage(String body);
+
+   MapMessage createMessage(Map<String, Object> body);
+
+   ObjectMessage createMessage(Serializable body);
+
+   BytesMessage createMessage(byte[] body, Map<String, Object> properties);
+
+   TextMessage createMessage(String body, Map<String, Object> properties);
+
+   MapMessage createMessage(Map<String, Object> body, Map<String, Object> properties);
+
+   ObjectMessage createMessage(Serializable body, Map<String, Object> properties);
+
+   void pushMessage(String destinationName, Message message);
+
+   BytesMessage pushMessage(String destinationName, byte[] body);
+
+   TextMessage pushMessage(String destinationName, String body);
+
+   MapMessage pushMessage(String destinationName, Map<String, Object> body);
+
+   ObjectMessage pushMessage(String destinationName, Serializable body);
+
+   BytesMessage pushMessageWithProperties(String destinationName, byte[] body, Map<String, Object> properties);
+
+   TextMessage pushMessageWithProperties(String destinationName, String body, Map<String, Object> properties);
+
+   MapMessage pushMessageWithProperties(String destinationName, Map<String, Object> body,
+                                        Map<String, Object> properties);
+
+   ObjectMessage pushMessageWithProperties(String destinationName, Serializable body, Map<String, Object> properties);
+
+   Message peekMessage(String destinationName);
+
+   BytesMessage peekBytesMessage(String destinationName);
+
+   TextMessage peekTextMessage(String destinationName);
+
+   MapMessage peekMapMessage(String destinationName);
+
+   ObjectMessage peekObjectMessage(String destinationName);
+
+   StreamMessage peekStreamMessage(String destinationName);
+
+}
\ No newline at end of file
diff --git a/artemis-junit/pom.xml b/artemis-junit/pom.xml
index 8eda779568..6721c4b58f 100644
--- a/artemis-junit/pom.xml
+++ b/artemis-junit/pom.xml
@@ -24,83 +24,18 @@
       <version>2.28.0-SNAPSHOT</version>
    </parent>
 
-   <artifactId>artemis-junit</artifactId>
-   <packaging>jar</packaging>
-   <name>ActiveMQ Artemis JUnit Rules</name>
+   <artifactId>artemis-junit-parent</artifactId>
+   <packaging>pom</packaging>
+   <name>ActiveMQ Artemis JUnit</name>
 
    <properties>
       <activemq.basedir>${project.basedir}/..</activemq.basedir>
    </properties>
 
-   <dependencies>
-      <dependency>
-         <groupId>junit</groupId>
-         <artifactId>junit</artifactId>
-         <scope>provided</scope>
-      </dependency>
-      <!-- logging -->
-      <dependency>
-         <groupId>org.slf4j</groupId>
-         <artifactId>slf4j-api</artifactId>
-      </dependency>
-      <dependency>
-         <groupId>org.apache.logging.log4j</groupId>
-         <artifactId>log4j-slf4j-impl</artifactId>
-         <scope>test</scope>
-      </dependency>
-      <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-jms-server</artifactId>
-         <version>${project.version}</version>
-      </dependency>
-      <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-jms-client</artifactId>
-         <version>${project.version}</version>
-      </dependency>
-      <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-server</artifactId>
-         <version>${project.version}</version>
-      </dependency>
-      <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-core-client</artifactId>
-         <version>${project.version}</version>
-      </dependency>
-      <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-commons</artifactId>
-         <version>${project.version}</version>
-      </dependency>
-
-      <dependency>
-         <groupId>jakarta.jms</groupId>
-         <artifactId>jakarta.jms-api</artifactId>
-      </dependency>
-
-      <dependency>
-         <groupId>org.apache.activemq</groupId>
-         <artifactId>artemis-unit-test-support</artifactId>
-         <version>${project.version}</version>
-         <scope>test</scope>
-      </dependency>
-
-
-      <!-- The johnzon-core and json-api contents are repackaged in -commons,
-     However maven can still need them during tests, which run against
-     the original -commons classes when built+run in the same reactor,
-     and not the jar containing the shaded bits. -->
-      <dependency>
-         <groupId>org.apache.johnzon</groupId>
-         <artifactId>johnzon-core</artifactId>
-         <scope>test</scope>
-      </dependency>
-      <dependency>
-         <groupId>jakarta.json</groupId>
-         <artifactId>jakarta.json-api</artifactId>
-         <scope>test</scope>
-      </dependency>
-   </dependencies>
+   <modules>
+      <module>artemis-junit-commons</module>
+      <module>artemis-junit-4</module>
+      <module>artemis-junit-5</module>
+   </modules>
 
 </project>
diff --git a/docs/user-manual/en/unit-testing.md b/docs/user-manual/en/unit-testing.md
index 7c909b7957..fc694ae236 100644
--- a/docs/user-manual/en/unit-testing.md
+++ b/docs/user-manual/en/unit-testing.md
@@ -1,25 +1,27 @@
 # Unit Testing
 
-The package `artemis-junit` provides tools to facilitate how to run Artemis resources inside JUnit Tests.
+Artemis resources can be run inside JUnit Tests by using provided Rules (for JUnit 4) or Extensions (for JUnit 5). This can make it easier to embed messaging functionality in your tests.
 
-These are provided as JUnit "rules" and can make it easier to embed messaging functionality on your tests.
+These are provided by the packages `artemis-junit` (JUnit 4) and `artemis-junit-5` (JUnit 5).
 
 
-## Example
+## Examples
 
-### Import this on your pom.xml
+### JUnit 4
+
+#### Add Maven dependency
 
 ```xml
 <dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>artemis-junit</artifactId>
    <!-- replace this for the version you are using -->
-   <version>2.5.0</version>
+   <version>@PROJECT_VERSION_FILTER_TOKEN@</version>
    <scope>test</scope>
 </dependency>
 ```
 
-### Declare a rule on your JUnit Test
+#### Declare a rule on your JUnit Test
 
 ```java
 import org.apache.activemq.artemis.junit.EmbeddedActiveMQResource;
@@ -29,43 +31,89 @@ import org.junit.Test;
 public class MyTest {
 
    @Rule
-   public EmbeddedActiveMQResource resource = new EmbeddedActiveMQResource();
+   public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
 
    @Test
    public void myTest() {
-
+     // test something, eg. create a queue
+     server.createQueue("test.adress", "test.queue");
    }
 }
 ```
 
-This will start a server that will be available for your test:
+### JUnit 5
 
+#### Add Maven dependency
+
+```xml
+<dependency>
+   <groupId>org.apache.activemq</groupId>
+   <artifactId>artemis-junit-5</artifactId>
+   <!-- replace this for the version you are using -->
+   <version>@PROJECT_VERSION_FILTER_TOKEN@</version>
+   <scope>test</scope>
+</dependency>
 ```
-[main] 17:00:16,644 INFO  [org.apache.activemq.artemis.core.server] AMQ221000: live Message Broker is starting with configuration Broker Configuration (clustered=false,journalDirectory=data/journal,bindingsDirectory=data/bindings,largeMessagesDirectory=data/largemessages,pagingDirectory=data/paging)
-[main] 17:00:16,666 INFO  [org.apache.activemq.artemis.core.server] AMQ221045: libaio is not available, switching the configuration into NIO
-[main] 17:00:16,688 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-server]. Adding protocol support for: CORE
-[main] 17:00:16,801 INFO  [org.apache.activemq.artemis.core.server] AMQ221007: Server is now live
-[main] 17:00:16,801 INFO  [org.apache.activemq.artemis.core.server] AMQ221001: Apache ActiveMQ Artemis Message Broker version 2.5.0-SNAPSHOT [embedded-server, nodeID=39e78380-842c-11e6-9e43-f45c8992f3c7]
-[main] 17:00:16,891 INFO  [org.apache.activemq.artemis.core.server] AMQ221002: Apache ActiveMQ Artemis Message Broker version 2.5.0-SNAPSHOT [39e78380-842c-11e6-9e43-f45c8992f3c7] stopped, uptime 0.272 seconds
+
+#### Declare a rule on your JUnit Test
+
+```java
+import org.apache.activemq.artemis.junit.EmbeddedActiveMQExtension;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+public class MyTest {
+
+   @RegisterExtension
+   public EmbeddedActiveMQExtension server = new EmbeddedActiveMQExtension();
+
+   @Test
+   public void myTest() {
+     // test something, eg. create a queue
+     server.createQueue("test.adress", "test.queue");
+   }
+}
 ```
 
-### Ordering rules
 
-This is actually a JUnit feature, but this could be helpful on pre-determining the order on which rules are executed. 
+## Ordering rules / extensions
+
+This is actually a JUnit feature, but this could be helpful on pre-determining the order on which rules are executed.
+
+### JUnit 4 
 
 ```java
-ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
+import org.junit.Rule;
+import org.junit.rules.RuleChain;
+
+public EmbeddedActiveMQResource server = new EmbeddedActiveMQResource();
+public ActiveMQDynamicProducerResource producer = new ActiveMQDynamicProducerResource(server.getVmURL());
 
 @Rule
-public RuleChain ruleChain = RuleChain.outerRule(new ThreadLeakCheckRule()).around(server).around(producer);
+public RuleChain ruleChain = RuleChain.outerRule(server).around(producer);
+```
+
+### JUnit 5 
+
+```java
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+@RegisterExtension
+@Order(1)
+public EmbeddedActiveMQExtension producer = new EmbeddedActiveMQExtension();
+
+@RegisterExtension
+@Order(2)
+public ActiveMQDynamicProducerExtension producer = new ActiveMQDynamicProducerExtension(server.getVmURL());
 ```
 
-### Available Rules
+## Available Rules / Extensions
 
-Name | Description
---- | ---
-EmbeddedActiveMQResource | Run a Server, without the JMS manager	
-EmbeddedJMSResource | Run a Server, including the JMS Manager
-ActiveMQConsumerResource | Automate the creation of a consumer		
-ActiveMQProducerResource | Automate the creation of a producer
-ThreadLeakCheckRule | Check that all threads have been finished after the test is finished
+JUnit 4 Rule | JUnit 5 Extension | Description
+--- | --- | ---
+EmbeddedActiveMQResource | EmbeddedActiveMQExtension | Run a Server, without the JMS manager	
+EmbeddedJMSResource | EmbeddedJMSExtension | Run a Server, including the JMS Manager
+ActiveMQConsumerResource | ActiveMQConsumerExtension | Automate the creation of a consumer		
+ActiveMQDynamicProducerResource | ActiveMQDynamicProducerExtension | Automate the creation of a producer
+ActiveMQProducerResource | ActiveMQProducerExtension | Automate the creation of a producer
diff --git a/pom.xml b/pom.xml
index b6f48878e5..ae419584e9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -150,6 +150,7 @@
       <version.micrometer>1.9.5</version.micrometer>
       <hamcrest.version>2.1</hamcrest.version>
       <junit.version>4.13.2</junit.version>
+      <junit5.version>5.8.2</junit5.version>
       <surefire.version>2.22.2</surefire.version>
       <version.jaxb.runtime>2.3.3</version.jaxb.runtime>
       <paho.client.mqtt.version>1.2.5</paho.client.mqtt.version>
@@ -284,13 +285,39 @@
    <dependencyManagement>
       <dependencies>
          <!-- ## Test Dependencies ## -->
+         <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>${junit5.version}</version>
+            <!-- Eclipse Public License - v 2.0 -->
+         </dependency>
+
+         <!-- ## Test Dependencies ## Note: Run Junit5 test. -->
+         <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>${junit5.version}</version>
+            <scope>test</scope>
+            <!-- Eclipse Public License - v 2.0 -->
+         </dependency>
+
+         <!-- ## Test Dependencies ## Note: Run Junit4 tests. -->
+         <dependency>
+            <groupId>org.junit.vintage</groupId>
+            <artifactId>junit-vintage-engine</artifactId>
+            <version>${junit5.version}</version>
+            <!-- Eclipse Public License - v 2.0 -->
+         </dependency>
+
+         <!-- ## Test Dependencies ## Note: Junit 4 is required in certain module tests.  We should control versions from here. -->
          <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>${junit.version}</version>
             <scope>test</scope>
-            <!-- License: EPL 1.0 -->
+            <!-- License: CPL 1.0 -->
          </dependency>
+         
          <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymock</artifactId>