http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/aerogear/pom.xml ---------------------------------------------------------------------- diff --git a/examples/jms/aerogear/pom.xml b/examples/jms/aerogear/pom.xml new file mode 100644 index 0000000..e0d22e6 --- /dev/null +++ b/examples/jms/aerogear/pom.xml @@ -0,0 +1,139 @@ +<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.hornetq.examples.jms</groupId> + <artifactId>jms-examples</artifactId> + <version>2.5.0-SNAPSHOT</version> + </parent> + + <properties> + <endpoint></endpoint> + <applicationid></applicationid> + <mastersecret></mastersecret> + </properties> + + <artifactId>hornetq-jms-aerogear-example</artifactId> + <packaging>jar</packaging> + <name>HornetQ JMS AeroGear Example</name> + + <dependencies> + <dependency> + <groupId>org.hornetq.examples.jms</groupId> + <artifactId>hornetq-jms-examples-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.spec.javax.jms</groupId> + <artifactId>jboss-jms-api_2.0_spec</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-maven-plugin</artifactId> + <executions> + <execution> + <id>start</id> + <goals> + <goal>start</goal> + </goals> + <configuration> + <systemProperties> + <property> + <name>build.directory</name> + <value>${basedir}/target/</value> + </property> + <property> + <name>endpoint</name> + <value>${endpoint}</value> + </property> + <property> + <name>applicationid</name> + <value>${applicationid}</value> + </property> + <property> + <name>mastersecret</name> + <value>${mastersecret}</value> + </property> + </systemProperties> + </configuration> + </execution> + <execution> + <id>runClient</id> + <goals> + <goal>runClient</goal> + </goals> + <configuration> + <clientClass>org.hornetq.jms.example.AerogearExample</clientClass> + <args> + <param>jnp://localhost:1099</param> + </args> + </configuration> + </execution> + <execution> + <id>stop</id> + <goals> + <goal>stop</goal> + </goals> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.hornetq.examples.jms</groupId> + <artifactId>hornetq-jms-aerogear-example</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-core-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-jms-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-jms-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-aerogear-integration</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + <version>${netty.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.javaee</groupId> + <artifactId>jboss-jms-api</artifactId> + <version>1.1.0.GA</version> + </dependency> + <dependency> + <groupId>org.jboss.naming</groupId> + <artifactId>jnpserver</artifactId> + <version>5.0.3.GA</version> + </dependency> + </dependencies> + <configuration> + <waitOnStart>false</waitOnStart> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server0</hornetqConfigurationDir> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/aerogear/readme.html ---------------------------------------------------------------------- diff --git a/examples/jms/aerogear/readme.html b/examples/jms/aerogear/readme.html new file mode 100644 index 0000000..66112a0 --- /dev/null +++ b/examples/jms/aerogear/readme.html @@ -0,0 +1,135 @@ +<html> + <head> + <title>HornetQ 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> + + <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/hornetq/HornetQAeroGear.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 HornetQServer</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 HornetQ</p> + + <p>Now lets look a bit more closely at the configuration in hornetq-configuration.xml</p> + <ol> + <pre class="prettyprint"> + <code> + <queues> + <queue name="jms.queue.aerogearQueue"> + <address>jms.queue.aerogearQueue</address> + </queue> + </queues> + + <connector-services> + <connector-service name="aerogear-connector"> + <factory-class>org.hornetq.integration.aerogear.AeroGearConnectorServiceFactory</factory-class> + <param key="endpoint" value="${endpoint}"/> + <param key="queue" value="jms.queue.aerogearQueue"/> + <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/aerogearQueue"); + + // 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 HornetQ"); + + 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> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java ---------------------------------------------------------------------- diff --git a/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java b/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java new file mode 100644 index 0000000..a0d285a --- /dev/null +++ b/examples/jms/aerogear/src/main/java/org/hornetq/jms/example/AerogearExample.java @@ -0,0 +1,92 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat licenses this file to you under the Apache License, version + * 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.hornetq.jms.example; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.InitialContext; + +import org.hornetq.common.example.HornetQExample; + +/** + * A simple JMS Queue example that creates a producer and consumer on a queue and sends then receives a message. + * + * @author <a href="atay...@redhat.com">Andy Taylor</a> + */ +public class AerogearExample extends HornetQExample +{ + public static void main(final String[] args) + { + new AerogearExample().run(args); + } + + @Override + public boolean runExample() throws Exception + { + Connection connection = null; + InitialContext initialContext = null; + try + { + // Step 1. Create an initial context to perform the JNDI lookup. + initialContext = getContext(0); + + // Step 2. Perfom a lookup on the queue + Queue queue = (Queue)initialContext.lookup("/queue/aerogearQueue"); + + // 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 HornetQ"); + + producer.send(message); + + System.out.println("Sent message"); + + System.out.println("now check your mobile app and press enter"); + + System.in.read(); + + return true; + } + finally + { + // Step 12. 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-6/blob/8ecd255f/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml ---------------------------------------------------------------------- diff --git a/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml new file mode 100644 index 0000000..6100121 --- /dev/null +++ b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-configuration.xml @@ -0,0 +1,61 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd"> + + <bindings-directory>${build.directory}/server0/data/messaging/bindings</bindings-directory> + + <journal-directory>${build.directory}/server0/data/messaging/journal</journal-directory> + + <large-messages-directory>${build.directory}/server0/data/messaging/largemessages</large-messages-directory> + + <paging-directory>${build.directory}/server0/data/messaging/paging</paging-directory> + + + <!-- Connectors --> + + <connectors> + <connector name="netty-connector"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class> + </connector> + </connectors> + + <!-- Acceptors --> + <acceptors> + <acceptor name="netty-acceptor"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class> + </acceptor> + </acceptors> + + <!-- We need to create a core queue for the JMS queue explicitly because the connector will be deployed + before the JMS queue is deployed, so the first time, it otherwise won't find the queue --> + <queues> + <queue name="jms.queue.aerogearQueue"> + <address>jms.queue.aerogearQueue</address> + </queue> + </queues> + + <connector-services> + <connector-service name="aerogear-connector"> + <factory-class>org.hornetq.integration.aerogear.AeroGearConnectorServiceFactory</factory-class> + <param key="endpoint" value="${endpoint}"/> + <param key="queue" value="jms.queue.aerogearQueue"/> + <param key="application-id" value="${applicationid}"/> + <param key="master-secret" value="${mastersecret}"/> + </connector-service> + </connector-services> + + <!-- Other config --> + + <security-settings> + <!--security for example queue--> + <security-setting match="jms.queue.aerogearQueue"> + <permission type="createDurableQueue" roles="guest"/> + <permission type="deleteDurableQueue" roles="guest"/> + <permission type="createNonDurableQueue" roles="guest"/> + <permission type="deleteNonDurableQueue" roles="guest"/> + <permission type="consume" roles="guest"/> + <permission type="send" roles="guest"/> + </security-setting> + </security-settings> + +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml ---------------------------------------------------------------------- diff --git a/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml new file mode 100644 index 0000000..cde44e7 --- /dev/null +++ b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-jms.xml @@ -0,0 +1,19 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"> + <!--the connection factory used by the example--> + <connection-factory name="ConnectionFactory"> + <connectors> + <connector-ref connector-name="netty-connector"/> + </connectors> + <entries> + <entry name="ConnectionFactory"/> + </entries> + </connection-factory> + + <!--the queue used by the example--> + <queue name="aerogearQueue"> + <entry name="/queue/aerogearQueue"/> + </queue> + +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml ---------------------------------------------------------------------- diff --git a/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml new file mode 100644 index 0000000..934306c --- /dev/null +++ b/examples/jms/aerogear/src/main/resources/hornetq/server0/hornetq-users.xml @@ -0,0 +1,7 @@ +<configuration xmlns="urn:hornetq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-users.xsd"> + <!-- the default user. this is used where username is null--> + <defaultuser name="guest" password="guest"> + <role name="guest"/> + </defaultuser> +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/applet.html ---------------------------------------------------------------------- diff --git a/examples/jms/applet/applet.html b/examples/jms/applet/applet.html new file mode 100644 index 0000000..f7b7b80 --- /dev/null +++ b/examples/jms/applet/applet.html @@ -0,0 +1,17 @@ +<html> + <head> + <title>HornetQ Applet Example</title> + </head> + <body> + <h1>HornetQ Applet Example</h1> + + <p>The Applet will connect to HornetQ server running on localhost and + publishes messages on a topic <code>exampleTopic</code> when "Send" is pressed.</p> + <p>The Applet is also a MessageListener and will display messages received from the topic</p> + + <applet code="org.hornetq.jms.example.AppletExample.class" + codebase="build/classes/" + archive="hornetq-core-client.jar,hornetq-jms-client.jar,jboss-jms-api.jar,netty.jar" + width="640" height="480"></applet> + </body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/pom.xml ---------------------------------------------------------------------- diff --git a/examples/jms/applet/pom.xml b/examples/jms/applet/pom.xml new file mode 100644 index 0000000..db34e33 --- /dev/null +++ b/examples/jms/applet/pom.xml @@ -0,0 +1,129 @@ +<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.hornetq.examples.jms</groupId> + <artifactId>jms-examples</artifactId> + <version>2.5.0-SNAPSHOT</version> + </parent> + + <artifactId>hornetq-jms-applet-example</artifactId> + <packaging>jar</packaging> + <name>HornetQ JMS Applet Example</name> + + <dependencies> + <dependency> + <groupId>org.hornetq.examples.jms</groupId> + <artifactId>hornetq-jms-examples-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + </dependency> + <dependency> + <groupId>org.jboss.spec.javax.jms</groupId> + <artifactId>jboss-jms-api_2.0_spec</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-maven-plugin</artifactId> + <executions> + <execution> + <id>start0</id> + <goals> + <goal>start</goal> + </goals> + <configuration> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server0</hornetqConfigurationDir> + </configuration> + </execution> + <execution> + <id>runClient</id> + <goals> + <goal>runClient</goal> + </goals> + <configuration> + <clientClass>org.hornetq.jms.example.AppletExample</clientClass> + <args> + <param>jnp://localhost:1099</param> + </args> + <systemProperties> + <property> + <name>exampleConfigDir</name> + <value>${basedir}/target/classes/hornetq</value> + </property> + </systemProperties> + </configuration> + </execution> + <execution> + <id>stop0</id> + <goals> + <goal>stop</goal> + </goals> + <configuration> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server0</hornetqConfigurationDir> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.hornetq.examples.jms</groupId> + <artifactId>hornetq-jms-applet-example</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-core-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-jms-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-jms-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + <version>${netty.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.javaee</groupId> + <artifactId>jboss-jms-api</artifactId> + <version>1.1.0.GA</version> + </dependency> + <dependency> + <groupId>org.jboss.naming</groupId> + <artifactId>jnpserver</artifactId> + <version>5.0.3.GA</version> + </dependency> + </dependencies> + <configuration> + <waitOnStart>false</waitOnStart> + <systemProperties> + <property> + <name>build.directory</name> + <value>${basedir}/target/</value> + </property> + </systemProperties> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/readme.html ---------------------------------------------------------------------- diff --git a/examples/jms/applet/readme.html b/examples/jms/applet/readme.html new file mode 100644 index 0000000..e954316 --- /dev/null +++ b/examples/jms/applet/readme.html @@ -0,0 +1,21 @@ +<html> + <head> + <title>HornetQ Applet 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>Applet Example</h1> + <p>This example shows you how to send and receive JMS messages from an Applet.</p> + + <h2>Example step-by-step</h2> + + <p><i>To run the example, simply type <code>mvn verify</code> from this directory</i> to start + the HornetQ server and an HTTP server.</p> + + <p>Then, go to <a href="http://127.0.0.1:8088/applet.html">http://127.0.0.1:8088/applet.html</a> to load + and use the applet.</p> + + </body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/java/org/hornetq/jms/example/AppletExample.java ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/java/org/hornetq/jms/example/AppletExample.java b/examples/jms/applet/src/main/java/org/hornetq/jms/example/AppletExample.java new file mode 100644 index 0000000..4d09780 --- /dev/null +++ b/examples/jms/applet/src/main/java/org/hornetq/jms/example/AppletExample.java @@ -0,0 +1,290 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat licenses this file to you under the Apache License, version + * 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.hornetq.jms.example; + +import java.awt.Color; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.swing.BorderFactory; +import javax.swing.JApplet; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; + +import org.hornetq.api.core.TransportConfiguration; +import org.hornetq.api.jms.HornetQJMSClient; +import org.hornetq.api.jms.JMSFactoryType; +import org.hornetq.core.remoting.impl.netty.NettyConnectorFactory; + +/** + * A AppletExample + * + * @author <a href="mailto:jmes...@redaht.com>Jeff Mesnil</a> + * + * + */ +public class AppletExample extends JApplet implements ActionListener +{ + + // Constants ----------------------------------------------------- + + // Attributes ---------------------------------------------------- + + // Static -------------------------------------------------------- + + // Constructors -------------------------------------------------- + + /** + * + */ + private static final long serialVersionUID = -2129589098734805722L; + + private Destination destination; + + private Connection connection; + + private MessageProducer producer; + + private MessageConsumer consumer; + + private JTextArea display; + + private JButton sendButton; + + private Session session; + + @Override + public void init() + { + super.init(); + + try + { + SwingUtilities.invokeAndWait(new Runnable() + { + public void run() + { + createGUI(); + } + }); + } + catch (Exception e) + { + System.err.println("createGUI didn't successfully complete"); + } + + Map<String, Object> params = new HashMap<String, Object>(); + TransportConfiguration connector = new TransportConfiguration(NettyConnectorFactory.class.getName(), params); + ConnectionFactory cf = (ConnectionFactory)HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, connector); + destination = HornetQJMSClient.createTopic("exampleTopic"); + + try + { + connection = cf.createConnection(); + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + producer = session.createProducer(destination); + consumer = session.createConsumer(destination); + consumer.setMessageListener(new MessageListener() + { + public void onMessage(final Message msg) + { + try + { + SwingUtilities.invokeAndWait(new Runnable() + { + public void run() + { + try + { + display.setText(display.getText() + "\n" + ((TextMessage)msg).getText()); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + }); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + }); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + @Override + public void start() + { + super.start(); + + try + { + connection.start(); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + @Override + public void stop() + { + System.out.println("close connection"); + if (connection != null) + { + try + { + connection.close(); + } + catch (JMSException e) + { + e.printStackTrace(); + } + } + + super.stop(); + + } + + // Public -------------------------------------------------------- + + public static void main(final String[] args) throws Exception + { + + final AppletExample applet = new AppletExample(); + applet.init(); + + JFrame frame = new JFrame("Applet Example"); + frame.getContentPane().add(applet); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + + applet.start(); + System.out.println("open up the applet.html file in a browser, press enter to stop the example"); + System.in.read(); + Runtime.getRuntime().addShutdownHook(new Thread() + { + @Override + public void run() + { + applet.stop(); + } + }); + } + + public void actionPerformed(final ActionEvent e) + { + try + { + producer.send(session.createTextMessage(new Date().toString())); + } + catch (JMSException e1) + { + e1.printStackTrace(); + } + } + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + private void createGUI() + { + JPanel contentPane = new JPanel(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + int numColumns = 3; + + JLabel l1 = new JLabel("Received Messages:", SwingConstants.CENTER); + c.gridx = 0; + c.gridy = 0; + c.anchor = GridBagConstraints.SOUTH; + c.gridwidth = numColumns; + contentPane.add(l1, c); + + display = new JTextArea(5, 20); + JScrollPane scrollPane = new JScrollPane(display); + display.setEditable(false); + display.setForeground(Color.gray); + c.gridy = 1; + c.gridwidth = numColumns; + c.anchor = GridBagConstraints.CENTER; + c.weighty = 1.0; + c.fill = GridBagConstraints.BOTH; + contentPane.add(scrollPane, c); + + sendButton = new JButton("Send"); + c.gridy = 2; + c.gridwidth = 1; + c.anchor = GridBagConstraints.SOUTH; + c.weighty = 0.0; + c.fill = GridBagConstraints.NONE; + contentPane.add(sendButton, c); + + sendButton.addActionListener(this); + + JButton clearButton = new JButton("Clear"); + c.gridx = 2; + c.weightx = 0.0; + c.anchor = GridBagConstraints.SOUTHEAST; + c.fill = GridBagConstraints.NONE; + contentPane.add(clearButton, c); + + clearButton.addActionListener(new ActionListener() + { + public void actionPerformed(final ActionEvent e) + { + display.setText(""); + } + }); + + // Finish setting up the content pane and its border. + contentPane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.black), + BorderFactory.createEmptyBorder(5, 20, 5, 10))); + setContentPane(contentPane); + } + + // Inner classes ------------------------------------------------- + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServer.java ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServer.java b/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServer.java new file mode 100644 index 0000000..89ffcba --- /dev/null +++ b/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServer.java @@ -0,0 +1,77 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat licenses this file to you under the Apache License, version + * 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.hornetq.jms.example; + +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; + +import org.hornetq.common.example.HornetQExample; +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; + +/** + * A HttpServer + * + * * @author The Netty Project (netty-...@lists.jboss.org) + * @author Trustin Lee (t...@redhat.com) + * @author <a href="mailto:jmes...@redhat.com>Jeff Mesnil</a> + * + * + */ +public class HttpStaticFileServer extends HornetQExample +{ + + public static void main(final String[] args) + { + new HttpStaticFileServer().run(args); + } + + @Override + public boolean runExample() throws Exception + { + // Configure the server. + ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), + Executors.newCachedThreadPool())); + // Set up the event pipeline factory. + bootstrap.setPipelineFactory(new HttpStaticFileServerPipelineFactory()); + // Bind and start to accept incoming connections. + bootstrap.bind(new InetSocketAddress(8088)); + + System.out.println("HTTP server ready to server on 8088"); + + System.out.println("open http://127.0.0.1:8088/applet.html to use the Applet"); + + while (true) + { + Thread.sleep(100); + } + + } + + // Attributes ---------------------------------------------------- + + // Static -------------------------------------------------------- + + // Constructors -------------------------------------------------- + + // Public -------------------------------------------------------- + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + // Inner classes ------------------------------------------------- + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerHandler.java ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerHandler.java b/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerHandler.java new file mode 100644 index 0000000..65fc6bf --- /dev/null +++ b/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerHandler.java @@ -0,0 +1,185 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat licenses this file to you under the Apache License, version + * 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.hornetq.jms.example; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelFutureListener; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipelineCoverage; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.handler.codec.frame.TooLongFrameException; +import org.jboss.netty.handler.codec.http.DefaultHttpResponse; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpResponse; +import org.jboss.netty.handler.codec.http.HttpResponseStatus; +import org.jboss.netty.handler.codec.http.HttpVersion; +import org.jboss.netty.handler.stream.ChunkedFile; + +/** + * A HttpStaticFileServerHandler + * + * @author The Netty Project (netty-...@lists.jboss.org) + * @author Trustin Lee (t...@redhat.com) + * @author <a href="mailto:jmes...@redhat.com>Jeff Mesnil</a> + * + * + */ +@ChannelPipelineCoverage("one") +public class HttpStaticFileServerHandler extends SimpleChannelUpstreamHandler +{ + + @Override + public void messageReceived(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception + { + HttpRequest request = (HttpRequest)e.getMessage(); + if (request.getMethod() != HttpMethod.GET) + { + sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED); + return; + } + + if (request.isChunked()) + { + sendError(ctx, HttpResponseStatus.BAD_REQUEST); + return; + } + + String path = sanitizeUri(request.getUri()); + if (path == null) + { + sendError(ctx, HttpResponseStatus.FORBIDDEN); + return; + } + + File file = new File(path); + if (file.isHidden() || !file.exists()) + { + sendError(ctx, HttpResponseStatus.NOT_FOUND); + return; + } + if (!file.isFile()) + { + sendError(ctx, HttpResponseStatus.FORBIDDEN); + return; + } + + RandomAccessFile raf; + try + { + raf = new RandomAccessFile(file, "r"); + } + catch (FileNotFoundException fnfe) + { + sendError(ctx, HttpResponseStatus.NOT_FOUND); + return; + } + long fileLength = raf.length(); + + HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); + response.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(fileLength)); + + Channel ch = e.getChannel(); + + // Write the initial line and the header. + ch.write(response); + + // Write the content. + ChannelFuture writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192)); + + // Decide whether to close the connection or not. + boolean close = HttpHeaders.Values.CLOSE.equalsIgnoreCase(request.getHeader(HttpHeaders.Names.CONNECTION)) || request.getProtocolVersion() + .equals(HttpVersion.HTTP_1_0) && + !HttpHeaders.Values.KEEP_ALIVE.equalsIgnoreCase(request.getHeader(HttpHeaders.Names.CONNECTION)); + + if (close) + { + // Close the connection when the whole content is written out. + writeFuture.addListener(ChannelFutureListener.CLOSE); + } + } + + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, final ExceptionEvent e) throws Exception + { + Channel ch = e.getChannel(); + Throwable cause = e.getCause(); + if (cause instanceof TooLongFrameException) + { + sendError(ctx, HttpResponseStatus.BAD_REQUEST); + return; + } + + cause.printStackTrace(); + if (ch.isConnected()) + { + sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR); + } + } + + private String sanitizeUri(String uri) + { + // Decode the path. + try + { + uri = URLDecoder.decode(uri, "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + try + { + uri = URLDecoder.decode(uri, "ISO-8859-1"); + } + catch (UnsupportedEncodingException e1) + { + throw new Error(); + } + } + + // Convert file separators. + uri = uri.replace('/', File.separatorChar); + + // Simplistic dumb security check. + // You will have to do something serious in the production environment. + if (uri.contains(File.separator + ".") || uri.contains("." + File.separator) || + uri.startsWith(".") || + uri.endsWith(".")) + { + return null; + } + + // Convert to absolute path. + return System.getProperty("user.dir") + File.separator + uri; + } + + private void sendError(final ChannelHandlerContext ctx, final HttpResponseStatus status) + { + HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status); + response.setHeader(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); + response.setContent(ChannelBuffers.copiedBuffer("Failure: " + status.toString() + "\r\n", "UTF-8")); + + // Close the connection as soon as the error message is sent. + ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerPipelineFactory.java ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerPipelineFactory.java b/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerPipelineFactory.java new file mode 100644 index 0000000..db639a0 --- /dev/null +++ b/examples/jms/applet/src/main/java/org/hornetq/jms/example/HttpStaticFileServerPipelineFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat licenses this file to you under the Apache License, version + * 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.hornetq.jms.example; + +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.handler.codec.http.HttpRequestDecoder; +import org.jboss.netty.handler.codec.http.HttpResponseEncoder; +import org.jboss.netty.handler.stream.ChunkedWriteHandler; + +/** + * A HttpStaticFileServerPipelineFactory + * + * @author The Netty Project (netty-...@lists.jboss.org) + * @author Trustin Lee (t...@redhat.com) + * @author <a href="mailto:jmes...@redhat.com>Jeff Mesnil</a> + * + * + */ +public class HttpStaticFileServerPipelineFactory implements ChannelPipelineFactory +{ + public ChannelPipeline getPipeline() throws Exception + { + // Create a default pipeline implementation. + ChannelPipeline pipeline = Channels.pipeline(); + + pipeline.addLast("decoder", new HttpRequestDecoder()); + pipeline.addLast("encoder", new HttpResponseEncoder()); + pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); + + pipeline.addLast("handler", new HttpStaticFileServerHandler()); + return pipeline; + } + + // Constants ----------------------------------------------------- + + // Attributes ---------------------------------------------------- + + // Static -------------------------------------------------------- + + // Constructors -------------------------------------------------- + + // Public -------------------------------------------------------- + + // Package protected --------------------------------------------- + + // Protected ----------------------------------------------------- + + // Private ------------------------------------------------------- + + // Inner classes ------------------------------------------------- + +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-configuration.xml ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-configuration.xml new file mode 100644 index 0000000..b5e4cd2 --- /dev/null +++ b/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-configuration.xml @@ -0,0 +1,41 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd"> + + <bindings-directory>${build.directory}/server0/data/messaging/bindings</bindings-directory> + + <journal-directory>${build.directory}/server0/data/messaging/journal</journal-directory> + + <large-messages-directory>${build.directory}/server0/data/messaging/largemessages</large-messages-directory> + + <paging-directory>${build.directory}/server0/data/messaging/paging</paging-directory> + + <!-- Connectors --> + <connectors> + <connector name="netty-connector"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class> + </connector> + </connectors> + + <!-- Acceptors --> + <acceptors> + <acceptor name="netty-acceptor"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class> + </acceptor> + </acceptors> + + <!-- Other config --> + + <security-settings> + <!--security for example topic--> + <security-setting match="jms.topic.exampleTopic"> + <permission type="createDurableQueue" roles="guest"/> + <permission type="deleteDurableQueue" roles="guest"/> + <permission type="createNonDurableQueue" roles="guest"/> + <permission type="deleteNonDurableQueue" roles="guest"/> + <permission type="consume" roles="guest"/> + <permission type="send" roles="guest"/> + </security-setting> + </security-settings> + +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-jms.xml ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-jms.xml new file mode 100644 index 0000000..f89d475 --- /dev/null +++ b/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-jms.xml @@ -0,0 +1,19 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"> + <!--the connection factory used by the example--> + <connection-factory name="ConnectionFactory"> + <connectors> + <connector-ref connector-name="netty-connector"/> + </connectors> + <entries> + <entry name="ConnectionFactory"/> + </entries> + </connection-factory> + + <!--the topic used by the example--> + <topic name="exampleTopic"> + <entry name="/topic/exampleTopic"/> + </topic> + +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-users.xml ---------------------------------------------------------------------- diff --git a/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-users.xml new file mode 100644 index 0000000..934306c --- /dev/null +++ b/examples/jms/applet/src/main/resources/hornetq/server0/hornetq-users.xml @@ -0,0 +1,7 @@ +<configuration xmlns="urn:hornetq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-users.xsd"> + <!-- the default user. this is used where username is null--> + <defaultuser name="guest" password="guest"> + <role name="guest"/> + </defaultuser> +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/pom.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/pom.xml b/examples/jms/application-layer-failover/pom.xml new file mode 100644 index 0000000..596e3a9 --- /dev/null +++ b/examples/jms/application-layer-failover/pom.xml @@ -0,0 +1,143 @@ +<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.hornetq.examples.jms</groupId> + <artifactId>jms-examples</artifactId> + <version>2.5.0-SNAPSHOT</version> + </parent> + + <artifactId>hornetq-jms-application-layer-failover-example</artifactId> + <packaging>jar</packaging> + <name>HornetQ JMS Application Layer Failover Example</name> + + <dependencies> + <dependency> + <groupId>org.hornetq.examples.jms</groupId> + <artifactId>hornetq-jms-examples-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.spec.javax.jms</groupId> + <artifactId>jboss-jms-api_2.0_spec</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-maven-plugin</artifactId> + <executions> + <execution> + <id>start0</id> + <goals> + <goal>start</goal> + </goals> + <configuration> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server0</hornetqConfigurationDir> + </configuration> + </execution> + <execution> + <id>start1</id> + <goals> + <goal>start</goal> + </goals> + <configuration> + <jndiPort>1199</jndiPort> + <jndiRmiPort>1198</jndiRmiPort> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server1</hornetqConfigurationDir> + <serverStartString>INFO: HQ221034</serverStartString> + <fork>true</fork> + </configuration> + </execution> + <execution> + <id>runClient</id> + <goals> + <goal>runClient</goal> + </goals> + <configuration> + <clientClass>org.hornetq.jms.example.ApplicationLayerFailoverExample</clientClass> + <args> + <param>jnp://localhost:1099</param> + <param>jnp://localhost:1199</param> + </args> + <systemProperties> + <property> + <name>exampleConfigDir</name> + <value>${basedir}/target/classes/hornetq</value> + </property> + </systemProperties> + </configuration> + </execution> + <execution> + <id>stop0</id> + <goals> + <goal>stop</goal> + </goals> + <configuration> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server0</hornetqConfigurationDir> + </configuration> + </execution> + <execution> + <id>stop1</id> + <goals> + <goal>stop</goal> + </goals> + <configuration> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server1</hornetqConfigurationDir> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.hornetq.examples.jms</groupId> + <artifactId>hornetq-jms-application-layer-failover-example</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-core-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-jms-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.hornetq</groupId> + <artifactId>hornetq-jms-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + <version>${netty.version}</version> + </dependency> + <dependency> + <groupId>org.jboss.javaee</groupId> + <artifactId>jboss-jms-api</artifactId> + <version>1.1.0.GA</version> + </dependency> + <dependency> + <groupId>org.jboss.naming</groupId> + <artifactId>jnpserver</artifactId> + <version>5.0.3.GA</version> + </dependency> + </dependencies> + <configuration> + <waitOnStart>false</waitOnStart> + <hornetqConfigurationDir>${basedir}/target/classes/hornetq/server0</hornetqConfigurationDir> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/readme.html ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/readme.html b/examples/jms/application-layer-failover/readme.html new file mode 100644 index 0000000..8fa4b32 --- /dev/null +++ b/examples/jms/application-layer-failover/readme.html @@ -0,0 +1,149 @@ +<html> + <head> + <title>HornetQ Application-Layer Failover 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>Application-Layer Failover Example</h1> + + <p>HornetQ implements fully transparent <b>automatic</b> failover of connections from a live node to a backup node which requires + no special coding. This is described in a different example and requires server replication.</p> + <p>However, HornetQ also supports <b>Application-Layer</b> failover which is useful in the case where replication is not enabled.</p> + <p>With Application-Layer failover, it's up to the application to register a JMS ExceptionListener with HornetQ. + This listener will then be called by HornetQ in the event that connection failure is detected.</p> + <p>User code in the ExceptionListener can then recreate any JMS Connection, Session, etc on another node and the application + can continue.</p> + <p>Application-Layer failover is an alternative approach to High Availabilty (HA).</p> + <p>Application-Layer failover differs from automatic failover in that some client side coding is required in order + to implement this. Also, with Application-Layer failover, since the old Session object dies and a new is created, any uncommitted + work in the old Session will be lost, and any unacknowledged messages might be redelivered.</p> + <p>For more information on HornetQ failover and HA, and clustering in general, please see the clustering + section of the user manual.</p> + + <h2>Example step-by-step</h2> + <p><i>To run the example, simply type <code>mvn verify</code> from this directory</i></p> + <p>In this example, the live server is server 1, which will failover onto server 0.</p> + <p>The connection will initially be created to server1, server 1 will crash, and the client will carry on + on server 0, the new server. With Application-Layer failover the node that is failed over onto, does not need to + be specially configured as a backup server, it can be any node.</p> + + <ol> + <li> We create our JMS Connection, Session, MessageProducer and MessageConsumer on server 1</li> + <pre class="prettyprint"> + <code>createJMSObjects(1);</code> + </pre> + + <li>We set a JMS ExceptionListener on the connection. On failure this will be called and the connection, + session, etc. will be manually recreated on the backup node.</li> + <pre class="prettyprint"> + <code>connection.setExceptionListener(new ExampleListener());</code> + </pre> + + <li>We send some messages to server 1, the live server.</li> + <pre class="prettyprint"> + <code> + final int numMessages = 10; + + for (int i = 0; i < numMessages; i++) + { + TextMessage message = session.createTextMessage("This is text message " + i); + + producer.send(message); + + System.out.println("Sent message: " + message.getText()); + } + </code> + </pre> + + <li>We consume those messages on server 1.</li> + <pre class="prettyprint"> + <code> + for (int i = 0; i < numMessages; i++) + { + TextMessage message0 = (TextMessage)consumer.receive(5000); + + System.out.println("Got message: " + message0.getText()); + } + </code> + </pre> + + <li>We now cause server 1, the live server to crash. After a little while the connection's + ExceptionListener will register the failure and reconnection will occur.</li> + <pre class="prettyprint"> + <code>killServer(1);</code> + </pre> + + <li>The connection's ExceptionListener gets called, and we lookup the JMS objects and + recreate the connection, session, etc on the other node 0.</li> + <pre class="prettyprint"> + <code> + private class ExampleListener implements ExceptionListener + { + public void onException(JMSException exception) + { + try + { + // Close the old resources + + closeResources(); + + // Create new JMS objects on the backup server + + createJMSObjects(0); + + failoverLatch.countDown(); + } + catch (Exception e) + { + System.err.println("Failed to handle failover"); + + e.printStackTrace(); + } + } + } + </code> + </pre> + + <li>We are now connected to the other node. We now send some more messages.</li> + <pre class="prettyprint"> + <code> + for (int i = numMessages; i < numMessages * 2; i++) + { + TextMessage message = session.createTextMessage("This is text message " + i); + + producer.send(message); + + System.out.println("Sent message: " + message.getText()); + } + </code> + </pre> + + <li>And consume them.</li> + <pre class="prettyprint"> + <code> + for (int i = 0; i < numMessages; i++) + { + TextMessage message0 = (TextMessage)consumer.receive(5000); + + System.out.println("Got message: " + message0.getText()); + } + </code> + </pre> + + + <li>And finally (no pun intended), <b>always</b> remember to close your 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 + { + closeResources(); + } + </code> + </pre> + + </ol> + </body> +</html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/java/org/hornetq/jms/example/ApplicationLayerFailoverExample.java ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/java/org/hornetq/jms/example/ApplicationLayerFailoverExample.java b/examples/jms/application-layer-failover/src/main/java/org/hornetq/jms/example/ApplicationLayerFailoverExample.java new file mode 100644 index 0000000..b6b8f8f --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/java/org/hornetq/jms/example/ApplicationLayerFailoverExample.java @@ -0,0 +1,237 @@ +/* + * Copyright 2005-2014 Red Hat, Inc. + * Red Hat licenses this file to you under the Apache License, version + * 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.hornetq.jms.example; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.ExceptionListener; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.InitialContext; + +import org.hornetq.common.example.HornetQExample; + +/** + * A simple example that demonstrates application-layer failover of the JMS connection from one node to another + * when the live server crashes + * + * @author <a href="tim....@jboss.com>Tim Fox</a> + */ +public class ApplicationLayerFailoverExample extends HornetQExample +{ + public static void main(final String[] args) + { + new ApplicationLayerFailoverExample().run(args); + } + + private volatile InitialContext initialContext; + + private volatile Connection connection; + + private volatile Session session; + + private volatile MessageConsumer consumer; + + private volatile MessageProducer producer; + + private final CountDownLatch failoverLatch = new CountDownLatch(1); + + @Override + public boolean runExample() throws Exception + { + try + { + // Step 1. We create our JMS Connection, Session, MessageProducer and MessageConsumer on server 1. + createJMSObjects(0); + + // Step 2. We set a JMS ExceptionListener on the connection. On failure this will be called and the connection, + // session, etc. will be then recreated on the backup node. + connection.setExceptionListener(new ExampleListener()); + + System.out.println("The initial JMS objects have been created, and the ExceptionListener set"); + + // Step 3. We send some messages to server 1, the live server + + final int numMessages = 10; + + for (int i = 0; i < numMessages; i++) + { + TextMessage message = session.createTextMessage("This is text message " + i); + + producer.send(message); + + System.out.println("Sent message: " + message.getText()); + } + + // Step 4. We consume those messages on server 1. + + for (int i = 0; i < numMessages; i++) + { + TextMessage message0 = (TextMessage)consumer.receive(5000); + + System.out.println("Got message: " + message0.getText()); + } + + // Step 5. We now cause server 1, the live server to crash. After a little while the connection's + // ExceptionListener will register the failure and reconnection will occur. + + System.out.println("Killing the server"); + + killServer(0, 1); + + // Step 6. Wait for the client side to register the failure and reconnect + + boolean ok = failoverLatch.await(5000, TimeUnit.MILLISECONDS); + + if (!ok) + { + return false; + } + + System.out.println("Reconnection has occurred. Now sending more messages."); + + // Step 8. We now send some more messages + + for (int i = numMessages; i < numMessages * 2; i++) + { + TextMessage message = session.createTextMessage("This is text message " + i); + + producer.send(message); + + System.out.println("Sent message: " + message.getText()); + } + + // Step 9. And consume them. + + for (int i = 0; i < numMessages; i++) + { + TextMessage message0 = (TextMessage)consumer.receive(5000); + + System.out.println("Got message: " + message0.getText()); + } + + return true; + } + catch(Throwable t) + { + t.printStackTrace(); + return false; + } + finally + { + // Step 14. Be sure to close our resources! + + closeResources(); + } + } + + private void createJMSObjects(final int server) throws Exception + { + // Step 1. Get an initial context for looking up JNDI from the server + initialContext = getContext(server); + + // Step 2. Look-up the JMS Queue object from JNDI + Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue"); + + // Step 3. Look-up a JMS Connection Factory object from JNDI on server 1 + ConnectionFactory connectionFactory = (ConnectionFactory)initialContext.lookup("/ConnectionFactory"); + + // Step 4. We create a JMS Connection connection + connection = connectionFactory.createConnection(); + + // Step 6. We start the connection to ensure delivery occurs + connection.start(); + + // Step 5. We create a JMS Session + session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + // Step 7. We create a JMS MessageConsumer object + consumer = session.createConsumer(queue); + + // Step 8. We create a JMS MessageProducer object + producer = session.createProducer(queue); + } + + private void closeResources() throws Exception + { + if (initialContext != null) + { + initialContext.close(); + } + + if (connection != null) + { + connection.close(); + } + } + + private class ExampleListener implements ExceptionListener + { + public void onException(final JMSException exception) + { + try + { + connection.close(); + } + catch (JMSException e) + { + //ignore + } + for(int i = 0; i < 10; i++) + { + try + { + // Step 7. The ExceptionListener gets called and we recreate the JMS objects on the new node + + System.out.println("Connection failure has been detected on a the client."); + + // Close the old resources + + // closeResources(); + + System.out.println("The old resources have been closed."); + + // Create new JMS objects on the backup server + + createJMSObjects(1); + + System.out.println("The new resources have been created."); + + failoverLatch.countDown(); + + return; + } + catch (Exception e) + { + System.out.println("Failed to handle failover, trying again."); + try + { + Thread.sleep(500); + } + catch (InterruptedException e1) + { + //ignored + } + } + } + System.out.println("tried 10 times to reconnect, giving up"); + } + } +} http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-configuration.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-configuration.xml b/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-configuration.xml new file mode 100644 index 0000000..deabd34 --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-configuration.xml @@ -0,0 +1,39 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd"> + + <!-- Connectors --> + <connectors> + <connector name="netty-connector"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class> + <param key="port" value="5445"/> + </connector> + </connectors> + + <!-- Acceptors --> + + <acceptors> + <acceptor name="netty-acceptor"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class> + <param key="port" value="5445"/> + </acceptor> + </acceptors> + + <!-- Other config --> + + <security-settings> + <!--security for example queue--> + <security-setting match="jms.queue.exampleQueue"> + <permission type="createDurableQueue" roles="guest"/> + <permission type="deleteDurableQueue" roles="guest"/> + <permission type="createNonDurableQueue" roles="guest"/> + <permission type="deleteNonDurableQueue" roles="guest"/> + <permission type="consume" roles="guest"/> + <permission type="send" roles="guest"/> + </security-setting> + </security-settings> + + <journal-directory>target/data/journal</journal-directory> + <bindings-directory>target/data/bindings</bindings-directory> + <large-messages-directory>target/data/large-messages</large-messages-directory> +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-jms.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-jms.xml b/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-jms.xml new file mode 100644 index 0000000..71b83dd --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-jms.xml @@ -0,0 +1,19 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"> + <!--the connection factory used by the example--> + <connection-factory name="ConnectionFactory"> + <connectors> + <connector-ref connector-name="netty-connector"/> + </connectors> + <entries> + <entry name="ConnectionFactory"/> + </entries> + </connection-factory> + + <!--the queue used by the example--> + <queue name="exampleQueue"> + <entry name="/queue/exampleQueue"/> + </queue> + +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-users.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-users.xml b/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-users.xml new file mode 100644 index 0000000..934306c --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/resources/hornetq/server0/hornetq-users.xml @@ -0,0 +1,7 @@ +<configuration xmlns="urn:hornetq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-users.xsd"> + <!-- the default user. this is used where username is null--> + <defaultuser name="guest" password="guest"> + <role name="guest"/> + </defaultuser> +</configuration> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-configuration.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-configuration.xml b/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-configuration.xml new file mode 100644 index 0000000..6b5b301 --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-configuration.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd"> + + <!-- Connectors --> + + <connectors> + <connector name="netty-connector"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyConnectorFactory</factory-class> + <param key="port" value="5446"/> + </connector> + </connectors> + + <!-- Acceptors --> + <acceptors> + <acceptor name="netty-acceptor"> + <factory-class>org.hornetq.core.remoting.impl.netty.NettyAcceptorFactory</factory-class> + <param key="port" value="5446"/> + </acceptor> + </acceptors> + + <!-- Other config --> + + <security-settings> + <!--security for example queue--> + <security-setting match="jms.queue.exampleQueue"> + <permission type="createDurableQueue" roles="guest"/> + <permission type="deleteDurableQueue" roles="guest"/> + <permission type="createNonDurableQueue" roles="guest"/> + <permission type="deleteNonDurableQueue" roles="guest"/> + <permission type="consume" roles="guest"/> + <permission type="send" roles="guest"/> + </security-setting> + </security-settings> + + <journal-directory>target/data/journal</journal-directory> + <bindings-directory>target/data/bindings</bindings-directory> + <large-messages-directory>target/data/large-messages</large-messages-directory> +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-jms.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-jms.xml b/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-jms.xml new file mode 100644 index 0000000..71b83dd --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-jms.xml @@ -0,0 +1,19 @@ +<configuration xmlns="urn:hornetq" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-jms.xsd"> + <!--the connection factory used by the example--> + <connection-factory name="ConnectionFactory"> + <connectors> + <connector-ref connector-name="netty-connector"/> + </connectors> + <entries> + <entry name="ConnectionFactory"/> + </entries> + </connection-factory> + + <!--the queue used by the example--> + <queue name="exampleQueue"> + <entry name="/queue/exampleQueue"/> + </queue> + +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-6/blob/8ecd255f/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-users.xml ---------------------------------------------------------------------- diff --git a/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-users.xml b/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-users.xml new file mode 100644 index 0000000..934306c --- /dev/null +++ b/examples/jms/application-layer-failover/src/main/resources/hornetq/server1/hornetq-users.xml @@ -0,0 +1,7 @@ +<configuration xmlns="urn:hornetq" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:hornetq /schema/hornetq-users.xsd"> + <!-- the default user. this is used where username is null--> + <defaultuser name="guest" password="guest"> + <role name="guest"/> + </defaultuser> +</configuration> \ No newline at end of file