You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by cl...@apache.org on 2017/12/19 03:26:32 UTC

[2/2] activemq-artemis git commit: [ARTEMIS-550] add section on migrating virtual topics and test to validate

[ARTEMIS-550] add section on migrating virtual topics and test to validate


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

Branch: refs/heads/master
Commit: a1a30fb7fda4873e4246103ec6498ba487f9e706
Parents: 2d81f2d
Author: gtully <ga...@gmail.com>
Authored: Thu Dec 14 16:30:56 2017 +0000
Committer: Clebert Suconic <cl...@apache.org>
Committed: Mon Dec 18 22:25:28 2017 -0500

----------------------------------------------------------------------
 artemis-website/pom.xml                         |  9 ++
 artemis-website/src/main/resources/index.html   |  1 +
 docs/migration-guide/en/SUMMARY.md              |  1 +
 docs/migration-guide/en/VirtualTopics.md        | 40 +++++++++
 .../integration/openwire/FQQNOpenWireTest.java  | 94 ++++++++++++++++++++
 5 files changed, 145 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/a1a30fb7/artemis-website/pom.xml
----------------------------------------------------------------------
diff --git a/artemis-website/pom.xml b/artemis-website/pom.xml
index 1f818a0..a858928 100644
--- a/artemis-website/pom.xml
+++ b/artemis-website/pom.xml
@@ -80,6 +80,7 @@
       <webapp-dir>${project.artifactId}-${project.version}</webapp-dir>
       <webapp-outdir-user-manual>${basedir}/target/classes/user-manual</webapp-outdir-user-manual>
       <webapp-outdir-hacking-guide>${basedir}/target/classes/hacking-guide</webapp-outdir-hacking-guide>
+      <webapp-outdir-migration-guide>${basedir}/target/classes/migration-guide</webapp-outdir-migration-guide>
 
       <frontend-maven-plugin-version>0.0.29</frontend-maven-plugin-version>
       <nodeVersion>v6.11.0</nodeVersion>
@@ -191,6 +192,14 @@
                                  <arg value="${basedir}/../docs/hacking-guide/en" />
                                  <arg value="${webapp-outdir-hacking-guide}" />
                               </exec>
+                              <mkdir dir="${webapp-outdir-migration-guide}" />
+                              <echo>executing ${gitbook.cmd}</echo>
+                              <exec executable="${gitbook.cmd}" failonerror="true">
+                                 <env key="PATH" path="${basedir}/node" />
+                                 <arg value="build" />
+                                 <arg value="${basedir}/../docs/migration-guide/en" />
+                                 <arg value="${webapp-outdir-migration-guide}" />
+                              </exec>
                            </target>
                         </configuration>
                         <goals>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/a1a30fb7/artemis-website/src/main/resources/index.html
----------------------------------------------------------------------
diff --git a/artemis-website/src/main/resources/index.html b/artemis-website/src/main/resources/index.html
index 25d6231..c44d9ad 100644
--- a/artemis-website/src/main/resources/index.html
+++ b/artemis-website/src/main/resources/index.html
@@ -55,6 +55,7 @@
             <li><a target="_blank" href="api/index.html">API</a></li>
             <li><a target="_blank" href="user-manual/index.html">User Manual</a></li>
             <li><a target="_blank" href="hacking-guide/index.html">Hacking Guide</a></li>
+            <li><a target="_blank" href="migration-guide/index.html">Migration Guide</a></li>
             <li><a href="examples/index.html">Examples</a></li>
             <li><a href="http://activemq.apache.org/artemis/">Apache ActiveMQ Artemis Website</a></li>
         </ul>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/a1a30fb7/docs/migration-guide/en/SUMMARY.md
----------------------------------------------------------------------
diff --git a/docs/migration-guide/en/SUMMARY.md b/docs/migration-guide/en/SUMMARY.md
index 21c9eed..3c30dd3 100644
--- a/docs/migration-guide/en/SUMMARY.md
+++ b/docs/migration-guide/en/SUMMARY.md
@@ -3,6 +3,7 @@
 * [Configuration](configuration.md)
 * [Connectors](connectors.md)
 * [Destinations](destinations.md)
+* [Virtual Topics](VirtualTopics.md)
 * [Authentication](authentication.md)
 * [Authorization](authorization.md)
 * [SSL](ssl.md)

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/a1a30fb7/docs/migration-guide/en/VirtualTopics.md
----------------------------------------------------------------------
diff --git a/docs/migration-guide/en/VirtualTopics.md b/docs/migration-guide/en/VirtualTopics.md
new file mode 100644
index 0000000..e0775ad
--- /dev/null
+++ b/docs/migration-guide/en/VirtualTopics.md
@@ -0,0 +1,40 @@
+Virtual Topics
+==============
+
+Virtual Topics (a specialisation of virtual destinations) in ActiveMQ 5.x typically address two different but related
+problems. Lets take each in turn:
+ 
+Shared access to a JMS durable topic subscription
+-------------------------------------------------
+With JMS1.1, a durable subscription is identified by the pair of clientId and subscriptionName. The clientId
+component must be unique to a connection on the broker. This means that the subscription is exclusive. It is
+not possible to load balance the stream of messages across consumers and quick failover is difficult because the
+existing connection state on the broker needs to be first disposed.
+With virtual topics, each subscription's stream of messages is redirected to a queue.
+ 
+JMS2.0 adds the possibility of shared subscriptions with new API's that are fully supported in Artemis.
+Secondly, Artemis uses a queue per topic subscriber model internally and it is possibly to directly address the
+subscription queue using it's Fully Qualified Queue name (FQQN).
+
+For example, a default 5.x consumer for topic `VirtualTopic.Orders` subscription `A`:
+```
+    ...
+    Queue subscriptionQueue = session.createQueue("Consumer.A.VirtualTopic.Orders");
+    session.createConsumer(subscriptionQueue);
+
+``` 
+would be replaced with an Artemis FQQN comprised of the address and queue.
+```
+    ...
+    Queue subscriptionQueue = session.createQueue("VirtualTopic.Orders::Consumer.A");
+    session.createConsumer(subscriptionQueue);
+```
+
+Durable topic subscribers in a network of brokers
+-------------------------------------------------
+The store and forward network bridges in 5.x create a durable subscriber per destination. As demand migrates across a
+network, duplicate durable subs get created on each node in the network but they do not migrate. The end result can
+result in duplicate message storage and ultimately duplicate delivery, which is not good.
+When durable subscribers map to virtual topic subscriber queues, the queues can migrate and the problem can be avoided.
+
+In Artemis, because a durable sub is modeled as a queue, this problem does not arise.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/a1a30fb7/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/FQQNOpenWireTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/FQQNOpenWireTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/FQQNOpenWireTest.java
index 91f4e24..ff819ec 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/FQQNOpenWireTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/openwire/FQQNOpenWireTest.java
@@ -39,7 +39,9 @@ import org.apache.activemq.artemis.core.postoffice.Binding;
 import org.apache.activemq.artemis.core.postoffice.Bindings;
 import org.apache.activemq.artemis.core.postoffice.impl.LocalQueueBinding;
 import org.apache.activemq.artemis.core.server.QueueQueryResult;
+import org.apache.activemq.artemis.core.server.impl.AddressInfo;
 import org.apache.activemq.artemis.utils.CompositeAddress;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -266,4 +268,96 @@ public class FQQNOpenWireTest extends OpenWireTestBase {
          }
       }
    }
+
+   @Test
+   public void testVirtualTopicFQQN() throws Exception {
+      Connection exConn = null;
+
+      SimpleString topic = new SimpleString("VirtualTopic.Orders");
+      SimpleString subscriptionQ = new SimpleString("Consumer.A");
+
+      this.server.addAddressInfo(new AddressInfo(topic, RoutingType.MULTICAST));
+      this.server.createQueue(topic, RoutingType.MULTICAST, subscriptionQ, null, true, false, -1, false, true);
+
+      try {
+         ActiveMQConnectionFactory exFact = new ActiveMQConnectionFactory();
+         exFact.setWatchTopicAdvisories(false);
+         exConn = exFact.createConnection();
+         exConn.start();
+
+         Session session = exConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         Destination destination = session.createTopic(topic.toString());
+         MessageProducer producer = session.createProducer(destination);
+
+         Destination destinationFQN = session.createQueue(CompositeAddress.toFullQN(topic, subscriptionQ).toString());
+         MessageConsumer messageConsumerA = session.createConsumer(destinationFQN);
+         MessageConsumer messageConsumerB = session.createConsumer(destinationFQN);
+
+         TextMessage message = session.createTextMessage("This is a text message");
+         producer.send(message);
+
+         // only one consumer should get the message
+         TextMessage messageReceivedA = (TextMessage) messageConsumerA.receive(2000);
+         TextMessage messageReceivedB = (TextMessage) messageConsumerB.receive(2000);
+
+         assertTrue((messageReceivedA == null || messageReceivedB == null));
+         String text = messageReceivedA != null ? messageReceivedA.getText() : messageReceivedB.getText();
+         assertEquals("This is a text message", text);
+
+         messageConsumerA.close();
+         messageConsumerB.close();
+
+      } finally {
+         if (exConn != null) {
+            exConn.close();
+         }
+      }
+   }
+
+   @Test
+   @Ignore("need to figure auto bindings creation")
+   public void testVirtualTopicFQQNAutoCreate() throws Exception {
+      Connection exConn = null;
+
+      SimpleString topic = new SimpleString("VirtualTopic.Orders");
+      SimpleString subscriptionQ = new SimpleString("Consumer.A");
+
+      this.server.getAddressSettingsRepository().getMatch("VirtualTopic.#").setAutoCreateQueues(true);
+      this.server.getAddressSettingsRepository().getMatch("VirtualTopic.#").setDefaultAddressRoutingType(RoutingType.MULTICAST);
+
+      try {
+         ActiveMQConnectionFactory exFact = new ActiveMQConnectionFactory();
+         exFact.setWatchTopicAdvisories(false);
+         exConn = exFact.createConnection();
+         exConn.start();
+
+         Session session = exConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+         Destination destination = session.createTopic(topic.toString());
+         MessageProducer producer = session.createProducer(destination);
+
+         Destination destinationFQN = session.createQueue(CompositeAddress.toFullQN(topic, subscriptionQ).toString());
+
+         MessageConsumer messageConsumerA = session.createConsumer(destinationFQN);
+         MessageConsumer messageConsumerB = session.createConsumer(destinationFQN);
+
+         TextMessage message = session.createTextMessage("This is a text message");
+         producer.send(message);
+
+         // only one consumer should get the message
+         TextMessage messageReceivedA = (TextMessage) messageConsumerA.receive(2000);
+         TextMessage messageReceivedB = (TextMessage) messageConsumerB.receive(2000);
+
+         assertTrue((messageReceivedA == null || messageReceivedB == null));
+         String text = messageReceivedA != null ? messageReceivedA.getText() : messageReceivedB.getText();
+         assertEquals("This is a text message", text);
+
+         messageConsumerA.close();
+         messageConsumerB.close();
+
+      } finally {
+         if (exConn != null) {
+            exConn.close();
+         }
+      }
+   }
 }