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 2015/08/13 06:13:20 UTC
[02/48] activemq-artemis git commit: renaming broker-features ->
features on examples
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-heuristic/readme.html
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-heuristic/readme.html b/examples/features/standard/xa-heuristic/readme.html
new file mode 100644
index 0000000..bf44937
--- /dev/null
+++ b/examples/features/standard/xa-heuristic/readme.html
@@ -0,0 +1,48 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html>
+ <head>
+ <title>ActiveMQ Artemis JMS XA Heuristic Example</title>
+ <link rel="stylesheet" type="text/css" href="../../../common/common.css" />
+ <link rel="stylesheet" type="text/css" href="../../../common/prettify.css" />
+ <script type="text/javascript" src="../../../common/prettify.js"></script>
+ </head>
+ <body onload="prettyPrint()">
+ <h1>JMS XA Heuristic Example</h1>
+
+ <pre>To run the example, simply type <b>mvn verify</b> from this directory, <br>or <b>mvn -PnoServer verify</b> if you want to start and create the server manually.</pre>
+
+ <p>This example shows you how to make an XA heuristic decision through the ActiveMQ Artemis Management Interface.</p>
+
+ <p>A heuristic decision is a unilateral decision to commit or rollback an XA transaction branch after it has
+ been prepared. </p>
+
+ <p>In this example we simulate a transaction manager to control the transactions. First we create an XASession
+ and enlist it in a transaction through its XAResource. We then send a text message, 'hello' and end/prepare the transaction
+ on the XAResource, but neither commit nor roll back the transaction. Another transaction is created and
+ associated with the same XAResource, and a second message, 'world' is sent on behalf of the second transaction. Again we leave
+ the second transaction in prepare state.
+ Then we get the MBeanServerConnection object to manipulate the prepared transactions. To illustrate, we roll back the first
+ transaction but commit the second. This will result in that only the message 'world' is received. </p>
+
+ <p>This example uses JMX to manipulate transactions in a ActiveMQ Artemis Server. For details on JMX facilities with ActiveMQ Artemis,
+ please look at the JMX Example.</p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java b/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
new file mode 100644
index 0000000..8b6be80
--- /dev/null
+++ b/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import javax.transaction.xa.Xid;
+
+import org.apache.activemq.artemis.utils.Base64;
+
+public class DummyXid implements Xid {
+
+ private static final long serialVersionUID = 407053232840068514L;
+
+ private final byte[] branchQualifier;
+
+ private final int formatId;
+
+ private final byte[] globalTransactionId;
+
+ private int hash;
+
+ private boolean hashCalculated;
+
+ // Static --------------------------------------------------------
+
+ public static String toBase64String(final Xid xid) {
+ return Base64.encodeBytes(DummyXid.toByteArray(xid));
+ }
+
+ private static byte[] toByteArray(final Xid xid) {
+ byte[] branchQualifier = xid.getBranchQualifier();
+ byte[] globalTransactionId = xid.getGlobalTransactionId();
+ int formatId = xid.getFormatId();
+
+ byte[] hashBytes = new byte[branchQualifier.length + globalTransactionId.length + 4];
+ System.arraycopy(branchQualifier, 0, hashBytes, 0, branchQualifier.length);
+ System.arraycopy(globalTransactionId, 0, hashBytes, branchQualifier.length, globalTransactionId.length);
+ byte[] intBytes = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ intBytes[i] = (byte) ((formatId >> i * 8) % 0xFF);
+ }
+ System.arraycopy(intBytes, 0, hashBytes, branchQualifier.length + globalTransactionId.length, 4);
+ return hashBytes;
+ }
+
+ // Constructors --------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param branchQualifier
+ * @param formatId
+ * @param globalTransactionId
+ */
+ public DummyXid(final byte[] branchQualifier, final int formatId, final byte[] globalTransactionId) {
+ this.branchQualifier = branchQualifier;
+ this.formatId = formatId;
+ this.globalTransactionId = globalTransactionId;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param other
+ */
+ public DummyXid(final Xid other) {
+ branchQualifier = copyBytes(other.getBranchQualifier());
+ formatId = other.getFormatId();
+ globalTransactionId = copyBytes(other.getGlobalTransactionId());
+ }
+
+ // Xid implementation ------------------------------------------------------------------
+
+ public byte[] getBranchQualifier() {
+ return branchQualifier;
+ }
+
+ public int getFormatId() {
+ return formatId;
+ }
+
+ public byte[] getGlobalTransactionId() {
+ return globalTransactionId;
+ }
+
+ // Public -------------------------------------------------------------------------------
+
+ @Override
+ public int hashCode() {
+ if (!hashCalculated) {
+ calcHash();
+ }
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Xid)) {
+ return false;
+ }
+ Xid xother = (Xid) other;
+ if (xother.getFormatId() != formatId) {
+ return false;
+ }
+ if (xother.getBranchQualifier().length != branchQualifier.length) {
+ return false;
+ }
+ if (xother.getGlobalTransactionId().length != globalTransactionId.length) {
+ return false;
+ }
+ for (int i = 0; i < branchQualifier.length; i++) {
+ byte[] otherBQ = xother.getBranchQualifier();
+ if (branchQualifier[i] != otherBQ[i]) {
+ return false;
+ }
+ }
+ for (int i = 0; i < globalTransactionId.length; i++) {
+ byte[] otherGtx = xother.getGlobalTransactionId();
+ if (globalTransactionId[i] != otherGtx[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "XidImpl (" + System.identityHashCode(this) +
+ " bq:" +
+ stringRep(branchQualifier) +
+ " formatID:" +
+ formatId +
+ " gtxid:" +
+ stringRep(globalTransactionId);
+ }
+
+ // Private -------------------------------------------------------------------------------
+
+ private String stringRep(final byte[] bytes) {
+ StringBuilder buff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ byte b = bytes[i];
+
+ buff.append(b);
+
+ if (i != bytes.length - 1) {
+ buff.append('.');
+ }
+ }
+
+ return buff.toString();
+ }
+
+ private void calcHash() {
+ byte[] hashBytes = org.apache.activemq.artemis.jms.example.DummyXid.toByteArray(this);
+ String s = new String(hashBytes);
+ hash = s.hashCode();
+ hashCalculated = true;
+ }
+
+ private byte[] copyBytes(final byte[] other) {
+ byte[] bytes = new byte[other.length];
+
+ System.arraycopy(other, 0, bytes, 0, other.length);
+
+ return bytes;
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/XAHeuristicExample.java
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/XAHeuristicExample.java b/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/XAHeuristicExample.java
new file mode 100644
index 0000000..d233731
--- /dev/null
+++ b/examples/features/standard/xa-heuristic/src/main/java/org/apache/activemq/artemis/jms/example/XAHeuristicExample.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.XAConnection;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XASession;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.naming.InitialContext;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import org.apache.activemq.artemis.api.core.management.ObjectNameBuilder;
+import org.apache.activemq.artemis.utils.UUIDGenerator;
+
+/**
+ * A simple JMS example showing how to administer un-finished transactions.
+ */
+public class XAHeuristicExample {
+
+ private static final String JMX_URL = "service:jmx:rmi:///jndi/rmi://localhost:3001/jmxrmi";
+
+ public static void main(final String[] args) throws Exception {
+ Boolean result = true;
+ final ArrayList<String> receiveHolder = new ArrayList<String>();
+ XAConnection connection = null;
+ InitialContext initialContext = null;
+ try {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = new InitialContext();
+
+ // Step 2. Lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the XA Connection Factory
+ XAConnectionFactory cf = (XAConnectionFactory) initialContext.lookup("XAConnectionFactory");
+
+ // Step 4.Create a JMS XAConnection
+ connection = cf.createXAConnection();
+
+ // Step 5. Start the connection
+ connection.start();
+
+ // Step 6. Create a JMS XASession
+ XASession xaSession = connection.createXASession();
+
+ // Step 7. Create a normal session
+ Session normalSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 8. Create a normal Message Consumer
+ MessageConsumer normalConsumer = normalSession.createConsumer(queue);
+ normalConsumer.setMessageListener(new SimpleMessageListener(receiveHolder, result));
+
+ // Step 9. Get the JMS Session
+ Session session = xaSession.getSession();
+
+ // Step 10. Create a message producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 11. Create two Text Messages
+ TextMessage helloMessage = session.createTextMessage("hello");
+ TextMessage worldMessage = session.createTextMessage("world");
+
+ // Step 12. create a transaction
+ Xid xid1 = new DummyXid("xa-example1".getBytes(StandardCharsets.ISO_8859_1), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
+
+ // Step 13. Get the JMS XAResource
+ XAResource xaRes = xaSession.getXAResource();
+
+ // Step 14. Begin the Transaction work
+ xaRes.start(xid1, XAResource.TMNOFLAGS);
+
+ // Step 15. do work, sending hello message.
+ producer.send(helloMessage);
+
+ System.out.println("Sent message " + helloMessage.getText());
+
+ // Step 16. Stop the work for xid1
+ xaRes.end(xid1, XAResource.TMSUCCESS);
+
+ // Step 17. Prepare xid1
+ xaRes.prepare(xid1);
+
+ // Step 18. Check none should be received
+ checkNoMessageReceived(receiveHolder);
+
+ // Step 19. Create another transaction.
+ Xid xid2 = new DummyXid("xa-example2".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
+
+ // Step 20. Begin the transaction work
+ xaRes.start(xid2, XAResource.TMNOFLAGS);
+
+ // Step 21. Send the second message
+ producer.send(worldMessage);
+
+ System.out.println("Sent message " + worldMessage.getText());
+
+ // Step 22. Stop the work for xid2
+ xaRes.end(xid2, XAResource.TMSUCCESS);
+
+ // Step 23. prepare xid2
+ xaRes.prepare(xid2);
+
+ // Step 24. Again, no messages should be received!
+ checkNoMessageReceived(receiveHolder);
+
+ // Step 25. Create JMX Connector to connect to the server's MBeanServer
+ JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(JMX_URL), new HashMap<String, String>());
+
+ // Step 26. Retrieve the MBeanServerConnection
+ MBeanServerConnection mbsc = connector.getMBeanServerConnection();
+
+ // Step 27. List the prepared transactions
+ ObjectName serverObject = ObjectNameBuilder.DEFAULT.getActiveMQServerObjectName();
+ String[] infos = (String[]) mbsc.invoke(serverObject, "listPreparedTransactions", null, null);
+
+ System.out.println("Prepared transactions: ");
+ for (String i : infos) {
+ System.out.println(i);
+ }
+
+ // Step 28. Roll back the first transaction
+ mbsc.invoke(serverObject, "rollbackPreparedTransaction", new String[]{DummyXid.toBase64String(xid1)}, new String[]{"java.lang.String"});
+
+ // Step 29. Commit the second one
+ mbsc.invoke(serverObject, "commitPreparedTransaction", new String[]{DummyXid.toBase64String(xid2)}, new String[]{"java.lang.String"});
+
+ Thread.sleep(2000);
+
+ // Step 30. Check the result, only the 'world' message received
+ checkMessageReceived("world", receiveHolder);
+
+ // Step 31. Check the prepared transaction again, should have none.
+ infos = (String[]) mbsc.invoke(serverObject, "listPreparedTransactions", null, null);
+ System.out.println("No. of prepared transactions now: " + infos.length);
+
+ // Step 32. Close the JMX Connector
+ connector.close();
+ }
+ finally {
+ // Step 32. Be sure to close our JMS resources!
+ if (initialContext != null) {
+ initialContext.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+
+ private static void checkMessageReceived(final String value, ArrayList<String> receiveHolder) {
+ if (receiveHolder.size() != 1) {
+ throw new IllegalStateException("Number of messages received not correct ! -- " + receiveHolder.size());
+ }
+ String msg = receiveHolder.get(0);
+ if (!msg.equals(value)) {
+ throw new IllegalStateException("Received message [" + msg + "], but we expect [" + value + "]");
+ }
+ receiveHolder.clear();
+ }
+
+ private static void checkNoMessageReceived(ArrayList<String> receiveHolder) {
+ if (receiveHolder.size() > 0) {
+ throw new IllegalStateException("Message received, wrong!");
+ }
+ receiveHolder.clear();
+ }
+}
+
+class SimpleMessageListener implements MessageListener {
+
+ ArrayList<String> receiveHolder;
+ Boolean result;
+
+ SimpleMessageListener(ArrayList<String> receiveHolder, Boolean result) {
+ this.receiveHolder = receiveHolder;
+ this.result = result;
+ }
+
+ public void onMessage(final Message message) {
+ try {
+ System.out.println("Message received: " + ((TextMessage) message).getText());
+ receiveHolder.add(((TextMessage) message).getText());
+ }
+ catch (JMSException e) {
+ result = false;
+ e.printStackTrace();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-heuristic/src/main/resources/jndi.properties
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-heuristic/src/main/resources/jndi.properties b/examples/features/standard/xa-heuristic/src/main/resources/jndi.properties
new file mode 100644
index 0000000..77561f7
--- /dev/null
+++ b/examples/features/standard/xa-heuristic/src/main/resources/jndi.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
+connectionFactory.ConnectionFactory=tcp://localhost:61616
+connectionFactory.XAConnectionFactory=tcp://localhost:61616?type=XA_CF
+queue.queue/exampleQueue=exampleQueue
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-receive/pom.xml
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-receive/pom.xml b/examples/features/standard/xa-receive/pom.xml
new file mode 100644
index 0000000..f421aaf
--- /dev/null
+++ b/examples/features/standard/xa-receive/pom.xml
@@ -0,0 +1,109 @@
+<?xml version='1.0'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.activemq.examples.broker</groupId>
+ <artifactId>jms-examples</artifactId>
+ <version>1.0.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>xa-receive</artifactId>
+ <packaging>jar</packaging>
+ <name>ActiveMQ Artemis JMS XA Receive Example</name>
+
+ <properties>
+ <activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>artemis-jms-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>artemis-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create</id>
+ <goals>
+ <goal>create</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ </configuration>
+ </execution>
+ <execution>
+ <id>start</id>
+ <goals>
+ <goal>cli</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <spawn>true</spawn>
+ <testURI>tcp://localhost:61616</testURI>
+ <args>
+ <param>run</param>
+ </args>
+ </configuration>
+ </execution>
+ <execution>
+ <id>runClient</id>
+ <goals>
+ <goal>runClient</goal>
+ </goals>
+ <configuration>
+ <clientClass>org.apache.activemq.artemis.jms.example.XAReceiveExample</clientClass>
+ </configuration>
+ </execution>
+ <execution>
+ <id>stop</id>
+ <goals>
+ <goal>cli</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <args>
+ <param>stop</param>
+ </args>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.activemq.examples.broker</groupId>
+ <artifactId>xa-receive</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-receive/readme.html
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-receive/readme.html b/examples/features/standard/xa-receive/readme.html
new file mode 100644
index 0000000..ab6d7d7
--- /dev/null
+++ b/examples/features/standard/xa-receive/readme.html
@@ -0,0 +1,48 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html>
+ <head>
+ <title>ActiveMQ Artemis JMS XA Receive Example</title>
+ <link rel="stylesheet" type="text/css" href="../../../common/common.css" />
+ <link rel="stylesheet" type="text/css" href="../../../common/prettify.css" />
+ <script type="text/javascript" src="../../../common/prettify.js"></script>
+ </head>
+ <body onload="prettyPrint()">
+ <h1>JMS XA Receive Example</h1>
+
+ <pre>To run the example, simply type <b>mvn verify</b> from this directory, <br>or <b>mvn -PnoServer verify</b> if you want to start and create the server manually.</pre>
+
+
+ <p>This example demonstrates receiving a message within the scope of an XA transaction. When using an XA transaction
+ the message will only be acknowledged and removed from the queue when the transaction is committed.
+ If the transaction is not committed the message maybe redelivered after rollback or during XA recovery.</p>
+
+ <p>ActiveMQ Artemis is JTA aware, meaning you can use ActiveMQ Artemis in an XA transactional environment
+ and participate in XA transactions. It provides the javax.transaction.xa.XAResource interface for that
+ purpose. Users can get a XAConnectionFactory to create XAConnections and XASessions.</p>
+
+ <p>In this example we simulate a transaction manager to control the transactions. First we create an XASession
+ for receiving and a normal session for sending. Then we start a new xa transaction and enlist the receiving
+ XASession through its XAResource. We then send two words, 'hello' and 'world', receive them, and let the
+ transaction roll back. The received messages are cancelled back to the queue. Next we start
+ a new transaction with the same XAResource enlisted, but this time we commit the transaction after receiving the
+ messages. Then we check that no more messages are to be received.</p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java b/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
new file mode 100644
index 0000000..4dbe2f8
--- /dev/null
+++ b/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import org.apache.activemq.artemis.utils.Base64;
+
+import javax.transaction.xa.Xid;
+
+public class DummyXid implements Xid {
+
+ private static final long serialVersionUID = 407053232840068514L;
+
+ private final byte[] branchQualifier;
+
+ private final int formatId;
+
+ private final byte[] globalTransactionId;
+
+ private int hash;
+
+ private boolean hashCalculated;
+
+ // Static --------------------------------------------------------
+
+ public static String toBase64String(final Xid xid) {
+ return Base64.encodeBytes(DummyXid.toByteArray(xid));
+ }
+
+ private static byte[] toByteArray(final Xid xid) {
+ byte[] branchQualifier = xid.getBranchQualifier();
+ byte[] globalTransactionId = xid.getGlobalTransactionId();
+ int formatId = xid.getFormatId();
+
+ byte[] hashBytes = new byte[branchQualifier.length + globalTransactionId.length + 4];
+ System.arraycopy(branchQualifier, 0, hashBytes, 0, branchQualifier.length);
+ System.arraycopy(globalTransactionId, 0, hashBytes, branchQualifier.length, globalTransactionId.length);
+ byte[] intBytes = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ intBytes[i] = (byte) ((formatId >> i * 8) % 0xFF);
+ }
+ System.arraycopy(intBytes, 0, hashBytes, branchQualifier.length + globalTransactionId.length, 4);
+ return hashBytes;
+ }
+
+ // Constructors --------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param branchQualifier
+ * @param formatId
+ * @param globalTransactionId
+ */
+ public DummyXid(final byte[] branchQualifier, final int formatId, final byte[] globalTransactionId) {
+ this.branchQualifier = branchQualifier;
+ this.formatId = formatId;
+ this.globalTransactionId = globalTransactionId;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param other
+ */
+ public DummyXid(final Xid other) {
+ branchQualifier = copyBytes(other.getBranchQualifier());
+ formatId = other.getFormatId();
+ globalTransactionId = copyBytes(other.getGlobalTransactionId());
+ }
+
+ // Xid implementation ------------------------------------------------------------------
+
+ public byte[] getBranchQualifier() {
+ return branchQualifier;
+ }
+
+ public int getFormatId() {
+ return formatId;
+ }
+
+ public byte[] getGlobalTransactionId() {
+ return globalTransactionId;
+ }
+
+ // Public -------------------------------------------------------------------------------
+
+ @Override
+ public int hashCode() {
+ if (!hashCalculated) {
+ calcHash();
+ }
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Xid)) {
+ return false;
+ }
+ Xid xother = (Xid) other;
+ if (xother.getFormatId() != formatId) {
+ return false;
+ }
+ if (xother.getBranchQualifier().length != branchQualifier.length) {
+ return false;
+ }
+ if (xother.getGlobalTransactionId().length != globalTransactionId.length) {
+ return false;
+ }
+ for (int i = 0; i < branchQualifier.length; i++) {
+ byte[] otherBQ = xother.getBranchQualifier();
+ if (branchQualifier[i] != otherBQ[i]) {
+ return false;
+ }
+ }
+ for (int i = 0; i < globalTransactionId.length; i++) {
+ byte[] otherGtx = xother.getGlobalTransactionId();
+ if (globalTransactionId[i] != otherGtx[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "XidImpl (" + System.identityHashCode(this) +
+ " bq:" +
+ stringRep(branchQualifier) +
+ " formatID:" +
+ formatId +
+ " gtxid:" +
+ stringRep(globalTransactionId);
+ }
+
+ // Private -------------------------------------------------------------------------------
+
+ private String stringRep(final byte[] bytes) {
+ StringBuilder buff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ byte b = bytes[i];
+
+ buff.append(b);
+
+ if (i != bytes.length - 1) {
+ buff.append('.');
+ }
+ }
+
+ return buff.toString();
+ }
+
+ private void calcHash() {
+ byte[] hashBytes = DummyXid.toByteArray(this);
+ String s = new String(hashBytes);
+ hash = s.hashCode();
+ hashCalculated = true;
+ }
+
+ private byte[] copyBytes(final byte[] other) {
+ byte[] bytes = new byte[other.length];
+
+ System.arraycopy(other, 0, bytes, 0, other.length);
+
+ return bytes;
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/XAReceiveExample.java
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/XAReceiveExample.java b/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/XAReceiveExample.java
new file mode 100644
index 0000000..4c4448d
--- /dev/null
+++ b/examples/features/standard/xa-receive/src/main/java/org/apache/activemq/artemis/jms/example/XAReceiveExample.java
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.XAConnection;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XASession;
+import javax.naming.InitialContext;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.activemq.artemis.utils.UUIDGenerator;
+
+/**
+ * A simple JMS example showing the usage of XA support in JMS.
+ */
+public class XAReceiveExample {
+
+ public static void main(final String[] args) throws Exception {
+ XAConnection connection = null;
+ InitialContext initialContext = null;
+ try {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = new InitialContext();
+
+ // Step 2. Lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the XA Connection Factory
+ XAConnectionFactory cf = (XAConnectionFactory) initialContext.lookup("XAConnectionFactory");
+
+ // Step 4.Create a JMS XAConnection
+ connection = cf.createXAConnection();
+
+ // Step 5. Start the connection
+ connection.start();
+
+ // Step 6. Create a JMS XASession
+ XASession xaSession = connection.createXASession();
+
+ // Step 7. Create a normal session
+ Session normalSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 8. Create a normal Message Producer
+ MessageProducer normalProducer = normalSession.createProducer(queue);
+
+ // Step 9. Get the JMS Session
+ Session session = xaSession.getSession();
+
+ // Step 10. Create a message consumer
+ MessageConsumer xaConsumer = session.createConsumer(queue);
+
+ // Step 11. Create two Text Messages
+ TextMessage helloMessage = session.createTextMessage("hello");
+ TextMessage worldMessage = session.createTextMessage("world");
+
+ // Step 12. create a transaction
+ Xid xid1 = new DummyXid("xa-example1".getBytes(StandardCharsets.US_ASCII), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
+
+ // Step 13. Get the JMS XAResource
+ XAResource xaRes = xaSession.getXAResource();
+
+ // Step 14. Begin the Transaction work
+ xaRes.start(xid1, XAResource.TMNOFLAGS);
+
+ // Step 15. Send two messages.
+ normalProducer.send(helloMessage);
+ normalProducer.send(worldMessage);
+
+ // Step 16. Receive the message
+ TextMessage rm1 = (TextMessage) xaConsumer.receive();
+ System.out.println("Message received: " + rm1.getText());
+ TextMessage rm2 = (TextMessage) xaConsumer.receive();
+ System.out.println("Message received: " + rm2.getText());
+
+ // Step 17. Stop the work
+ xaRes.end(xid1, XAResource.TMSUCCESS);
+
+ // Step 18. Prepare
+ xaRes.prepare(xid1);
+
+ // Step 19. Roll back the transaction
+ xaRes.rollback(xid1);
+
+ // Step 20. Create another transaction
+ Xid xid2 = new DummyXid("xa-example2".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
+
+ // Step 21. Start the transaction
+ xaRes.start(xid2, XAResource.TMNOFLAGS);
+
+ // Step 22. receive those messages again
+ rm1 = (TextMessage) xaConsumer.receive();
+ System.out.println("Message received again: " + rm1.getText());
+ rm2 = (TextMessage) xaConsumer.receive();
+ System.out.println("Message received again: " + rm2.getText());
+
+ // Step 23. Stop the work
+ xaRes.end(xid2, XAResource.TMSUCCESS);
+
+ // Step 24. Prepare
+ xaRes.prepare(xid2);
+
+ // Step 25. Commit!
+ xaRes.commit(xid2, false);
+
+ // Step 26. Check no more messages are received.
+ TextMessage rm3 = (TextMessage) xaConsumer.receive(2000);
+ if (rm3 == null) {
+ System.out.println("No message received after commit.");
+ }
+ else {
+ throw new IllegalStateException();
+ }
+ }
+ finally {
+ // Step 27. Be sure to close our JMS resources!
+ if (initialContext != null) {
+ initialContext.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-receive/src/main/resources/jndi.properties
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-receive/src/main/resources/jndi.properties b/examples/features/standard/xa-receive/src/main/resources/jndi.properties
new file mode 100644
index 0000000..77561f7
--- /dev/null
+++ b/examples/features/standard/xa-receive/src/main/resources/jndi.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
+connectionFactory.ConnectionFactory=tcp://localhost:61616
+connectionFactory.XAConnectionFactory=tcp://localhost:61616?type=XA_CF
+queue.queue/exampleQueue=exampleQueue
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-send/pom.xml
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-send/pom.xml b/examples/features/standard/xa-send/pom.xml
new file mode 100644
index 0000000..b4dfdf4
--- /dev/null
+++ b/examples/features/standard/xa-send/pom.xml
@@ -0,0 +1,109 @@
+<?xml version='1.0'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.activemq.examples.broker</groupId>
+ <artifactId>jms-examples</artifactId>
+ <version>1.0.1-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>xa-send</artifactId>
+ <packaging>jar</packaging>
+ <name>ActiveMQ Artemis JMS XA Send Example</name>
+
+ <properties>
+ <activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>artemis-jms-client</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>artemis-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create</id>
+ <goals>
+ <goal>create</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ </configuration>
+ </execution>
+ <execution>
+ <id>start</id>
+ <goals>
+ <goal>cli</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <spawn>true</spawn>
+ <testURI>tcp://localhost:61616</testURI>
+ <args>
+ <param>run</param>
+ </args>
+ </configuration>
+ </execution>
+ <execution>
+ <id>runClient</id>
+ <goals>
+ <goal>runClient</goal>
+ </goals>
+ <configuration>
+ <clientClass>org.apache.activemq.artemis.jms.example.XASendExample</clientClass>
+ </configuration>
+ </execution>
+ <execution>
+ <id>stop</id>
+ <goals>
+ <goal>cli</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <args>
+ <param>stop</param>
+ </args>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.activemq.examples.broker</groupId>
+ <artifactId>xa-send</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-send/readme.html
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-send/readme.html b/examples/features/standard/xa-send/readme.html
new file mode 100644
index 0000000..fb3db4c
--- /dev/null
+++ b/examples/features/standard/xa-send/readme.html
@@ -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.
+-->
+
+<html>
+ <head>
+ <title>ActiveMQ Artemis JMS XA Send Example</title>
+ <link rel="stylesheet" type="text/css" href="../../../common/common.css" />
+ <link rel="stylesheet" type="text/css" href="../../../common/prettify.css" />
+ <script type="text/javascript" src="../../../common/prettify.js"></script>
+ </head>
+ <body onload="prettyPrint()">
+ <h1>JMS XA Send Example</h1>
+ <p>This example shows you how message sending behaves in an XA transaction in ActiveMQ Artemis. When a message is sent within
+ the scope of an XA transaction, it will only reach the queue once the transaction is committed.
+ If the transaction is rolled back the sent messages will be discarded by the server.</p>
+
+ <p>ActiveMQ Artemis is JTA aware, meaning you can use ActiveMQ Artemis in a XA transactional environment
+ and participate in XA transactions. It provides the javax.transaction.xa.XAResource interface for that
+ purpose. Users can get a XAConnectionFactory to create XAConnections and XASessions.</p>
+
+ <p>In this example we simulate a transaction manager to control the transactions. First we create an XASession
+ and enlist it in a transaction through its XAResource. We then send two words, 'hello' and 'world', with
+ the session, let the transaction roll back. The messages are discarded and never be received. Next we start
+ a new transaction with the same XAResource, but this time we commit the transaction. Both messages are received.</p>
+
+ <h2>Example step-by-step</h2>
+ <p><i>To run the example, simply type <code>mvn verify -Pexample</code> from this directory</i></p>
+
+ <ol>
+ <li>First we need to get an initial context so we can look-up the JMS connection factory and destination objects from JNDI. This initial context will get it's properties from the <code>client-jndi.properties</code> file in the directory <code>../common/config</code></li>
+ <pre class="prettyprint">
+ <code>InitialContext initialContext = getContext(0);</code>
+ </pre>
+
+ <li>We look-up the JMS queue object from JNDI</li>
+ <pre class="prettyprint">
+ <code>Queue queue = (Queue) initialContext.lookup("/queue/exampleQueue");</code>
+ </pre>
+
+ <li>We perform a lookup on the XA Connection Factory</li>
+ <pre class="prettyprint">
+ <code>XAConnectionFactory cf = (XAConnectionFactory) initialContext.lookup("/XAConnectionFactory");</code>
+ </pre>
+
+ <li>We create a JMS XAConnection</li>
+ <pre class="prettyprint">
+ <code>connection = cf.createXAConnection();</code>
+ </pre>
+
+ <li>We Start the connection</li>
+ <pre class="prettyprint">
+ <code>connection.start();</code>
+ </pre>
+
+ <li>We create a JMS XASession</li>
+ <pre class="prettyprint">
+ <code>XASession xaSession = connection.createXASession();</code>
+ </pre>
+
+ <li>We create a normal session</li>
+ <pre class="prettyprint">
+ <code>Session normalSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);</code>
+ </pre>
+
+ <li>We create a normal Message Consumer</li>
+ <pre class="prettyprint">
+ <code>
+ MessageConsumer normalConsumer = normalSession.createConsumer(queue);
+ normalConsumer.setMessageListener(new SimpleMessageListener());
+ </code>
+ </pre>
+
+ <li>We get the JMS Session</li>
+ <pre class="prettyprint">
+ <code>Session session = xaSession.getSession();</code>
+ </pre>
+
+ <li>We create a message producer</li>
+ <pre class="prettyprint">
+ <code>MessageProducer producer = session.createProducer(queue);</code>
+ </pre>
+
+ <li>We create two Text Messages</li>
+ <pre class="prettyprint">
+ <code>
+ TextMessage helloMessage = session.createTextMessage("hello");
+ TextMessage worldMessage = session.createTextMessage("world");
+ </code>
+ </pre>
+
+ <li>We create a transaction</li>
+ <pre class="prettyprint">
+ <code>Xid xid1 = new XidImpl("xa-example1".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());</code>
+ </pre>
+
+ <li>We get the JMS XAResource</li>
+ <pre class="prettyprint">
+ <code>XAResource xaRes = xaSession.getXAResource();</code>
+ </pre>
+
+ <li>We begin the Transaction work</li>
+ <pre class="prettyprint">
+ <code>xaRes.start(xid1, XAResource.TMNOFLAGS);</code>
+ </pre>
+
+ <li>We do work, sending two messages.</li>
+ <pre class="prettyprint">
+ <code>
+ producer.send(helloMessage);
+ producer.send(worldMessage);
+ </code>
+ </pre>
+
+ <li>We check the result, it should receive none!</li>
+ <pre class="prettyprint">
+ <code>checkNoMessageReceived();</code>
+ </pre>
+
+ <li>We stop the work</li>
+ <pre class="prettyprint">
+ <code>xaRes.end(xid1, XAResource.TMSUCCESS);</code>
+ </pre>
+
+ <li>We prepare</li>
+ <pre class="prettyprint">
+ <code>xaRes.prepare(xid1);</code>
+ </pre>
+
+ <li>We roll back the transaction </li>
+ <pre class="prettyprint">
+ <code>xaRes.rollback(xid1);</code>
+ </pre>
+
+ <li>We check no messages should be received! </li>
+ <pre class="prettyprint">
+ <code>checkNoMessageReceived();</code>
+ </pre>
+
+ <li>We create another transaction</li>
+ <pre class="prettyprint">
+ <code>Xid xid2 = new XidImpl("xa-example2".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());</code>
+ </pre>
+
+ <li>We start the transaction</li>
+ <pre class="prettyprint">
+ <code>xaRes.start(xid2, XAResource.TMNOFLAGS);</code>
+ </pre>
+
+ <li>We re-send those messages</li>
+ <pre class="prettyprint">
+ <code>
+ producer.send(helloMessage);
+ producer.send(worldMessage);
+ </code>
+ </pre>
+
+ <li>We stop the work</li>
+ <pre class="prettyprint">
+ <code>xaRes.end(xid2, XAResource.TMSUCCESS);</code>
+ </pre>
+
+ <li>We prepare</li>
+ <pre class="prettyprint">
+ <code>xaRes.prepare(xid2);</code>
+ </pre>
+
+ <li>We check that no messages should be received at this moment</li>
+ <pre class="prettyprint">
+ <code>checkNoMessageReceived();</code>
+ </pre>
+
+ <li>We commit!</li>
+ <pre class="prettyprint">
+ <code>xaRes.commit(xid2, false);</code>
+ </pre>
+
+ <li>We check that all messages are received.</li>
+ <pre class="prettyprint">
+ <code>checkAllMessageReceived();</code>
+ </pre>
+
+ <li>And finally, <b>always</b> remember to close your JMS connections and resources after use, in a <code>finally</code> block. Closing a JMS connection will automatically close all of its sessions, consumers, producer and browser objects</li>
+
+ <pre class="prettyprint">
+ <code>finally
+ {
+ if (initialContext != null)
+ {
+ initialContext.close();
+ }
+ if (connection != null)
+ {
+ connection.close();
+ }
+ }</code>
+ </pre>
+ </ol>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java b/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
new file mode 100644
index 0000000..4dbe2f8
--- /dev/null
+++ b/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/DummyXid.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import org.apache.activemq.artemis.utils.Base64;
+
+import javax.transaction.xa.Xid;
+
+public class DummyXid implements Xid {
+
+ private static final long serialVersionUID = 407053232840068514L;
+
+ private final byte[] branchQualifier;
+
+ private final int formatId;
+
+ private final byte[] globalTransactionId;
+
+ private int hash;
+
+ private boolean hashCalculated;
+
+ // Static --------------------------------------------------------
+
+ public static String toBase64String(final Xid xid) {
+ return Base64.encodeBytes(DummyXid.toByteArray(xid));
+ }
+
+ private static byte[] toByteArray(final Xid xid) {
+ byte[] branchQualifier = xid.getBranchQualifier();
+ byte[] globalTransactionId = xid.getGlobalTransactionId();
+ int formatId = xid.getFormatId();
+
+ byte[] hashBytes = new byte[branchQualifier.length + globalTransactionId.length + 4];
+ System.arraycopy(branchQualifier, 0, hashBytes, 0, branchQualifier.length);
+ System.arraycopy(globalTransactionId, 0, hashBytes, branchQualifier.length, globalTransactionId.length);
+ byte[] intBytes = new byte[4];
+ for (int i = 0; i < 4; i++) {
+ intBytes[i] = (byte) ((formatId >> i * 8) % 0xFF);
+ }
+ System.arraycopy(intBytes, 0, hashBytes, branchQualifier.length + globalTransactionId.length, 4);
+ return hashBytes;
+ }
+
+ // Constructors --------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param branchQualifier
+ * @param formatId
+ * @param globalTransactionId
+ */
+ public DummyXid(final byte[] branchQualifier, final int formatId, final byte[] globalTransactionId) {
+ this.branchQualifier = branchQualifier;
+ this.formatId = formatId;
+ this.globalTransactionId = globalTransactionId;
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param other
+ */
+ public DummyXid(final Xid other) {
+ branchQualifier = copyBytes(other.getBranchQualifier());
+ formatId = other.getFormatId();
+ globalTransactionId = copyBytes(other.getGlobalTransactionId());
+ }
+
+ // Xid implementation ------------------------------------------------------------------
+
+ public byte[] getBranchQualifier() {
+ return branchQualifier;
+ }
+
+ public int getFormatId() {
+ return formatId;
+ }
+
+ public byte[] getGlobalTransactionId() {
+ return globalTransactionId;
+ }
+
+ // Public -------------------------------------------------------------------------------
+
+ @Override
+ public int hashCode() {
+ if (!hashCalculated) {
+ calcHash();
+ }
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Xid)) {
+ return false;
+ }
+ Xid xother = (Xid) other;
+ if (xother.getFormatId() != formatId) {
+ return false;
+ }
+ if (xother.getBranchQualifier().length != branchQualifier.length) {
+ return false;
+ }
+ if (xother.getGlobalTransactionId().length != globalTransactionId.length) {
+ return false;
+ }
+ for (int i = 0; i < branchQualifier.length; i++) {
+ byte[] otherBQ = xother.getBranchQualifier();
+ if (branchQualifier[i] != otherBQ[i]) {
+ return false;
+ }
+ }
+ for (int i = 0; i < globalTransactionId.length; i++) {
+ byte[] otherGtx = xother.getGlobalTransactionId();
+ if (globalTransactionId[i] != otherGtx[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "XidImpl (" + System.identityHashCode(this) +
+ " bq:" +
+ stringRep(branchQualifier) +
+ " formatID:" +
+ formatId +
+ " gtxid:" +
+ stringRep(globalTransactionId);
+ }
+
+ // Private -------------------------------------------------------------------------------
+
+ private String stringRep(final byte[] bytes) {
+ StringBuilder buff = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ byte b = bytes[i];
+
+ buff.append(b);
+
+ if (i != bytes.length - 1) {
+ buff.append('.');
+ }
+ }
+
+ return buff.toString();
+ }
+
+ private void calcHash() {
+ byte[] hashBytes = DummyXid.toByteArray(this);
+ String s = new String(hashBytes);
+ hash = s.hashCode();
+ hashCalculated = true;
+ }
+
+ private byte[] copyBytes(final byte[] other) {
+ byte[] bytes = new byte[other.length];
+
+ System.arraycopy(other, 0, bytes, 0, other.length);
+
+ return bytes;
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/XASendExample.java
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/XASendExample.java b/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/XASendExample.java
new file mode 100644
index 0000000..fd87f61
--- /dev/null
+++ b/examples/features/standard/xa-send/src/main/java/org/apache/activemq/artemis/jms/example/XASendExample.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.jms.TextMessage;
+import javax.jms.XAConnection;
+import javax.jms.XAConnectionFactory;
+import javax.jms.XASession;
+import javax.naming.InitialContext;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.activemq.artemis.utils.UUIDGenerator;
+
+/**
+ * A simple JMS example showing the usage of XA support in JMS.
+ */
+public class XASendExample {
+
+ public static void main(final String[] args) throws Exception {
+ AtomicBoolean result = new AtomicBoolean(true);
+ final ArrayList<String> receiveHolder = new ArrayList<String>();
+ XAConnection connection = null;
+ InitialContext initialContext = null;
+ try {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = new InitialContext();
+
+ // Step 2. Lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the XA Connection Factory
+ XAConnectionFactory cf = (XAConnectionFactory) initialContext.lookup("XAConnectionFactory");
+
+ // Step 4.Create a JMS XAConnection
+ connection = cf.createXAConnection();
+
+ // Step 5. Start the connection
+ connection.start();
+
+ // Step 6. Create a JMS XASession
+ XASession xaSession = connection.createXASession();
+
+ // Step 7. Create a normal session
+ Session normalSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 8. Create a normal Message Consumer
+ MessageConsumer normalConsumer = normalSession.createConsumer(queue);
+ normalConsumer.setMessageListener(new SimpleMessageListener(receiveHolder, result));
+
+ // Step 9. Get the JMS Session
+ Session session = xaSession.getSession();
+
+ // Step 10. Create a message producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 11. Create two Text Messages
+ TextMessage helloMessage = session.createTextMessage("hello");
+ TextMessage worldMessage = session.createTextMessage("world");
+
+ // Step 12. create a transaction
+ Xid xid1 = new DummyXid("xa-example1".getBytes(StandardCharsets.UTF_8), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
+
+ // Step 13. Get the JMS XAResource
+ XAResource xaRes = xaSession.getXAResource();
+
+ // Step 14. Begin the Transaction work
+ xaRes.start(xid1, XAResource.TMNOFLAGS);
+
+ // Step 15. do work, sending two messages.
+ producer.send(helloMessage);
+ producer.send(worldMessage);
+
+ Thread.sleep(2000);
+
+ // Step 16. Check the result, it should receive none!
+ checkNoMessageReceived(receiveHolder);
+
+ // Step 17. Stop the work
+ xaRes.end(xid1, XAResource.TMSUCCESS);
+
+ // Step 18. Prepare
+ xaRes.prepare(xid1);
+
+ // Step 19. Roll back the transaction
+ xaRes.rollback(xid1);
+
+ // Step 20. No messages should be received!
+ checkNoMessageReceived(receiveHolder);
+
+ // Step 21. Create another transaction
+ Xid xid2 = new DummyXid("xa-example2".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes());
+
+ // Step 22. Start the transaction
+ xaRes.start(xid2, XAResource.TMNOFLAGS);
+
+ // Step 23. Re-send those messages
+ producer.send(helloMessage);
+ producer.send(worldMessage);
+
+ // Step 24. Stop the work
+ xaRes.end(xid2, XAResource.TMSUCCESS);
+
+ // Step 25. Prepare
+ xaRes.prepare(xid2);
+
+ // Step 26. No messages should be received at this moment
+ checkNoMessageReceived(receiveHolder);
+
+ // Step 27. Commit!
+ xaRes.commit(xid2, false);
+
+ Thread.sleep(2000);
+
+ // Step 28. Check the result, all message received
+ checkAllMessageReceived(receiveHolder);
+
+ if (!result.get())
+ throw new IllegalStateException();
+ }
+ finally {
+ // Step 29. Be sure to close our JMS resources!
+ if (initialContext != null) {
+ initialContext.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+
+ private static void checkAllMessageReceived(ArrayList<String> receiveHolder) {
+ if (receiveHolder.size() != 2) {
+ throw new IllegalStateException("Number of messages received not correct ! -- " + receiveHolder.size());
+ }
+ receiveHolder.clear();
+ }
+
+ private static void checkNoMessageReceived(ArrayList<String> receiveHolder) {
+ if (receiveHolder.size() > 0) {
+ throw new IllegalStateException("Message received, wrong!");
+ }
+ receiveHolder.clear();
+ }
+}
+
+class SimpleMessageListener implements MessageListener {
+
+ ArrayList<String> receiveHolder;
+ AtomicBoolean result;
+
+ public SimpleMessageListener(ArrayList<String> receiveHolder, AtomicBoolean result) {
+ this.receiveHolder = receiveHolder;
+ this.result = result;
+ }
+
+ public void onMessage(final Message message) {
+ try {
+ System.out.println("Message received: " + message);
+ receiveHolder.add(((TextMessage) message).getText());
+ }
+ catch (JMSException e) {
+ result.set(false);
+ e.printStackTrace();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/standard/xa-send/src/main/resources/jndi.properties
----------------------------------------------------------------------
diff --git a/examples/features/standard/xa-send/src/main/resources/jndi.properties b/examples/features/standard/xa-send/src/main/resources/jndi.properties
new file mode 100644
index 0000000..77561f7
--- /dev/null
+++ b/examples/features/standard/xa-send/src/main/resources/jndi.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
+connectionFactory.ConnectionFactory=tcp://localhost:61616
+connectionFactory.XAConnectionFactory=tcp://localhost:61616?type=XA_CF
+queue.queue/exampleQueue=exampleQueue
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/sub-modules/aerogear/pom.xml
----------------------------------------------------------------------
diff --git a/examples/features/sub-modules/aerogear/pom.xml b/examples/features/sub-modules/aerogear/pom.xml
new file mode 100644
index 0000000..c522d78
--- /dev/null
+++ b/examples/features/sub-modules/aerogear/pom.xml
@@ -0,0 +1,125 @@
+<?xml version='1.0'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.activemq.examples.modules</groupId>
+ <artifactId>broker-modules</artifactId>
+ <version>1.0.1-SNAPSHOT</version>
+ </parent>
+
+ <properties>
+ <endpoint/>
+ <applicationid/>
+ <mastersecret/>
+ <activemq.basedir>${project.basedir}/../../../..</activemq.basedir>
+ </properties>
+
+ <artifactId>aerogear</artifactId>
+ <packaging>jar</packaging>
+ <name>ActiveMQ Artemis JMS AeroGear Example</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>artemis-cli</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.activemq</groupId>
+ <artifactId>artemis-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create</id>
+ <goals>
+ <goal>create</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <!-- this list was extracted from mvn dependency:tree on integration/aerogear -->
+ <libList>
+ <param>org.apache.activemq:artemis-aerogear-integration:${project.version}</param>
+ <param>org.jboss.aerogear:unifiedpush-java-client:1.0.0</param>
+ <param>net.iharder:base64:2.3.8</param>
+ <param>com.fasterxml.jackson.core:jackson-annotations:2.3.0</param>
+ <param>com.fasterxml.jackson.core:jackson-core:2.3.0</param>
+ <param>org.jboss.resteasy:resteasy-jackson-provider:2.3.2.Final</param>
+ <param>org.codehaus.jackson:jackson-core-asl:1.8.5</param>
+ <param>org.codehaus.jackson:jackson-mapper-asl:1.8.5</param>
+ <param>org.codehaus.jackson:jackson-jaxrs:1.8.5</param>
+ <param>org.codehaus.jackson:jackson-xc:1.8.5</param>
+ </libList>
+ </configuration>
+ </execution>
+ <execution>
+ <id>start</id>
+ <goals>
+ <goal>cli</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <spawn>true</spawn>
+ <testURI>tcp://localhost:61616</testURI>
+ <args>
+ <param>run</param>
+ </args>
+ </configuration>
+ </execution>
+ <execution>
+ <id>runClient</id>
+ <goals>
+ <goal>runClient</goal>
+ </goals>
+ <configuration>
+ <clientClass>org.apache.activemq.artemis.jms.example.AerogearExample</clientClass>
+ </configuration>
+ </execution>
+ <execution>
+ <id>stop</id>
+ <goals>
+ <goal>cli</goal>
+ </goals>
+ <configuration>
+ <ignore>${noServer}</ignore>
+ <args>
+ <param>stop</param>
+ </args>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.activemq.examples.modules</groupId>
+ <artifactId>aerogear</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/sub-modules/aerogear/readme.html
----------------------------------------------------------------------
diff --git a/examples/features/sub-modules/aerogear/readme.html b/examples/features/sub-modules/aerogear/readme.html
new file mode 100644
index 0000000..3534a4c
--- /dev/null
+++ b/examples/features/sub-modules/aerogear/readme.html
@@ -0,0 +1,157 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html>
+ <head>
+ <title>ActiveMQ Artemis JMS AeroGear Example</title>
+ <link rel="stylesheet" type="text/css" href="../../../common/common.css" />
+ <link rel="stylesheet" type="text/css" href="../../../common/prettify.css" />
+ <script type="text/javascript" src="../../../common/prettify.js"></script>
+ </head>
+ <body onload="prettyPrint()">
+ <h1>JMS AeroGear Example</h1>
+
+
+ <pre>To run the example, simply type <b>mvn verify</b> from this directory, <br>or <b>mvn -PnoServer verify</b> if you want to start and create the server manually.</pre>
+
+ <p>This example shows how you can send a message to a mobile device by leveraging <a href="http://aerogear.org/push/">AeroGears push</a> technology which
+ provides support for different push notification technologies like Google Cloud Messaging, Apple's APNs or
+ Mozilla's SimplePush.</p>
+
+ <p>For this example you will need an AeroGear Application running somewhere, a good way to do this is to deploy the
+ Push Application on <href a="">openshift</href>, you can follow the AeroGear Push 0.X Quickstart.</p>
+
+ <p>Once you have created your AeroGear Push Application you can create a mobile application. Simply log into the application
+ on the web and create a new mobile application by clicking the 'create' button. Once created you will see an application id
+ and a master secret, you will need the later to run the example.</p>
+
+ <p>lastly you will need to create a variant. For this example we will be using Android so you will need to create a google project,
+ this <a href="http://aerogear.org/docs/guides/aerogear-push-android/google-setup/">article</a> explains how to do this.
+ Once created click on your app then click 'add' to add a variant. choose 'google cloud messaging', enter your google
+ API key and the project number from your google project and click create</p>
+
+ <p>Now before we run the example we need a mobile application to receive it. Writing a mobile app is beyond the scope
+ of this example but for testing purposes we have supplied an Android app you can use, simply install on your android phone.
+ It can be found <a href="http://downloads.jboss.org.apache.activemq/ActiveMQAeroGear.apk">here</a>. For a more in depth mobile
+ app example visit the AeroGear site.</p>
+
+ <p>Once you have installed the mobile app you will need to configure the following:</p>
+ <p>AeroGear Unified Push URL : This is the URL where your aerogear server is running, something like http://myapp-mydomain.rhcloud.com
+ AeroGear Variant ID : This is the ID of the variant you created in AeroGear
+ AeroGear Variant Secret : This is the secret for your variant
+ GCM Sender ID : this is the Google project Number you created on Google
+ Variant : you can use this to target messages if needed.
+ </p>
+
+ <p>Once you set all these correctly you should get a message saying your mobile app is registered, if you log into
+ your AeroGear app you should see it registered with the variant.</p>
+
+
+ <p>Now to run the example simply run the following command
+ 'mvn -Dendpoint=my aerogear url -Dapplicationid=my application id -Dmastersecret=my master secret -Djsse.enableSNIExtension=false clean verify'.
+ If you arent using java 7 you can omit the 'jsse.enableSNIExtension=false'</p>
+
+ <p>You should see something like this in your ActiveMQServer</p>
+ <ol>
+ <pre class="prettyprint">
+ <code>
+ Dec 04, 2013 3:25:39 PM org.jboss.aerogear.unifiedpush.SenderClient submitPayload
+ INFO: HTTP Response code from UnifiedPush Server: 302
+ Dec 04, 2013 3:25:39 PM org.jboss.aerogear.unifiedpush.SenderClient submitPayload
+ INFO: Performing redirect to 'https://myapp-mydomain.rhcloud.com/rest/sender/'
+ Dec 04, 2013 3:25:40 PM org.jboss.aerogear.unifiedpush.SenderClient submitPayload
+ INFO: HTTP Response code from UnifiedPush Server: 200
+ </code>
+ </pre>
+ </ol>
+ <p>And on your mobile app you should see a message from ActiveMQ</p>
+
+ <p>Now lets look a bit more closely at the configuration in broker.xml</p>
+ <ol>
+ <pre class="prettyprint">
+ <code>
+ <queues>
+ <queue name="jms.queue.exampleQueue">
+ <address>jms.queue.exampleQueue</address>
+ </queue>
+ </queues>
+
+ <connector-services>
+ <connector-service name="aerogear-connector">
+ <factory-class>org.apache.activemq.integration.aerogear.AeroGearConnectorServiceFactory</factory-class>
+ <param key="endpoint" value="${endpoint}"/>
+ <param key="queue" value="jms.queue.exampleQueue"/>
+ <param key="application-id" value="${applicationid}"/>
+ <param key="master-secret" value="${mastersecret}"/>
+ </connector-service>
+ </connector-services>
+ </code>
+ </pre>
+ </ol>
+ <p>Firstly you will see that we have to create a core queue so it is available when the connector is started, the following are mandatory parameters:</p>
+ <ol>
+ <li>endpoint - The endpoint or URL of you AeroGear application</li>
+ <li>queue - The name of the queue to consume from</li>
+ <li>application-id - The application id of your mobile application in AeroGear</li>
+ <li>master-secret - the secret of your mobile application in AeroGear</li>
+ </ol>
+ <p>as well as those there are also the following optional parameters</p>
+ <ol>
+ <li>ttl - The time to live for the message once AeroGear receives it</li>
+ <li>badge - The badge the mobile app should use for the notification</li>
+ <li>sound - The sound the mobile app should use for the notification</li>
+ <li>filter - A message filter(selector) to use on the connector</li>
+ <li>retry-interval - If an error occurs on send, how long before we try again</li>
+ <li>retry-attempts - How many times we should try to reconnect after an error</li>
+ <li>variants - A comma separated list of variants that should get the message</li>
+ <li>aliases - A list of aliases that should get the message</li>
+ <li>device-types - A list of device types that should get the message</li>
+ </ol>
+ <p>More in depth explanations of these can be found in the AeroGear docs.</p>
+ <p>Now lets look at a snippet of code we used to send the message for our JMS client</p>
+ <pre class="prettyprint">
+ <code>
+ Queue queue = (Queue)initialContext.lookup("queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ Message message = session.createMessage();
+
+ message.setStringProperty("AEROGEAR_ALERT", "Hello this is a notification from ActiveMQ");
+
+ producer.send(message);
+ </code>
+ </pre>
+ <p> The most important thing here is string propert we have set on the message, i.e. 'AEROGEAR_ALERT'. This is the
+ actual alert that is sent via AeroGear</p>
+ <p>As well as the alert itself you can override any of the above optional parameters in the same fashionby using the
+ following propert names: AEROGEAR_SOUND,AEROGEAR_BADGE,AEROGEAR_TTL,AEROGEAR_VARIANTS,AEROGEAR_ALIASES and AEROGEAR_DEVICE_TYPES</p>
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/sub-modules/aerogear/src/main/java/org/apache/activemq/artemis/jms/example/AerogearExample.java
----------------------------------------------------------------------
diff --git a/examples/features/sub-modules/aerogear/src/main/java/org/apache/activemq/artemis/jms/example/AerogearExample.java b/examples/features/sub-modules/aerogear/src/main/java/org/apache/activemq/artemis/jms/example/AerogearExample.java
new file mode 100644
index 0000000..b412d87
--- /dev/null
+++ b/examples/features/sub-modules/aerogear/src/main/java/org/apache/activemq/artemis/jms/example/AerogearExample.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.artemis.jms.example;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Message;
+import javax.jms.MessageProducer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import javax.naming.InitialContext;
+
+/**
+ * A simple JMS Queue example that creates a producer and consumer on a queue and sends then receives a message.
+ */
+public class AerogearExample {
+
+ public static void main(final String[] args) throws Exception {
+ Connection connection = null;
+ InitialContext initialContext = null;
+ try {
+ // Step 1. Create an initial context to perform the JNDI lookup.
+ initialContext = new InitialContext();
+
+ // Step 2. Perfom a lookup on the queue
+ Queue queue = (Queue) initialContext.lookup("queue/exampleQueue");
+
+ // Step 3. Perform a lookup on the Connection Factory
+ ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("ConnectionFactory");
+
+ // Step 4.Create a JMS Connection
+ connection = cf.createConnection();
+
+ // Step 5. Create a JMS Session
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Step 6. Create a JMS Message Producer
+ MessageProducer producer = session.createProducer(queue);
+
+ // Step 7. Create a Text Message
+ Message message = session.createMessage();
+
+ message.setStringProperty("AEROGEAR_ALERT", "Hello this is a notification from ActiveMQ");
+
+ producer.send(message);
+
+ System.out.println("Sent message");
+
+ System.out.println("now check your mobile app and press enter");
+
+ System.in.read();
+ }
+ finally {
+ // Step 12. Be sure to close our JMS resources!
+ if (initialContext != null) {
+ initialContext.close();
+ }
+ if (connection != null) {
+ connection.close();
+ }
+ }
+ }
+}