[hornetq-commits] JBoss hornetq SVN: r8146 - in trunk: examples/jms and 20 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Tue Oct 27 06:18:03 EDT 2009


Author: jmesnil
Date: 2009-10-27 06:18:02 -0400 (Tue, 27 Oct 2009)
New Revision: 8146

Added:
   trunk/examples/jms/non-transaction-failover/
   trunk/examples/jms/non-transaction-failover/build.bat
   trunk/examples/jms/non-transaction-failover/build.sh
   trunk/examples/jms/non-transaction-failover/build.xml
   trunk/examples/jms/non-transaction-failover/readme.html
   trunk/examples/jms/non-transaction-failover/server0/
   trunk/examples/jms/non-transaction-failover/server0/client-jndi.properties
   trunk/examples/jms/non-transaction-failover/server0/hornetq-beans.xml
   trunk/examples/jms/non-transaction-failover/server0/hornetq-configuration.xml
   trunk/examples/jms/non-transaction-failover/server0/hornetq-jms.xml
   trunk/examples/jms/non-transaction-failover/server0/hornetq-users.xml
   trunk/examples/jms/non-transaction-failover/server1/
   trunk/examples/jms/non-transaction-failover/server1/KILL_ME
   trunk/examples/jms/non-transaction-failover/server1/client-jndi.properties
   trunk/examples/jms/non-transaction-failover/server1/hornetq-beans.xml
   trunk/examples/jms/non-transaction-failover/server1/hornetq-configuration.xml
   trunk/examples/jms/non-transaction-failover/server1/hornetq-jms.xml
   trunk/examples/jms/non-transaction-failover/server1/hornetq-users.xml
   trunk/examples/jms/non-transaction-failover/src/
   trunk/examples/jms/non-transaction-failover/src/org/
   trunk/examples/jms/non-transaction-failover/src/org/hornetq/
   trunk/examples/jms/non-transaction-failover/src/org/hornetq/jms/
   trunk/examples/jms/non-transaction-failover/src/org/hornetq/jms/example/
   trunk/examples/jms/non-transaction-failover/src/org/hornetq/jms/example/NonTransactionFailoverExample.java
   trunk/examples/jms/transaction-failover/
   trunk/examples/jms/transaction-failover/build.bat
   trunk/examples/jms/transaction-failover/build.sh
   trunk/examples/jms/transaction-failover/build.xml
   trunk/examples/jms/transaction-failover/readme.html
   trunk/examples/jms/transaction-failover/server0/
   trunk/examples/jms/transaction-failover/server0/client-jndi.properties
   trunk/examples/jms/transaction-failover/server0/hornetq-beans.xml
   trunk/examples/jms/transaction-failover/server0/hornetq-configuration.xml
   trunk/examples/jms/transaction-failover/server0/hornetq-jms.xml
   trunk/examples/jms/transaction-failover/server0/hornetq-users.xml
   trunk/examples/jms/transaction-failover/server1/
   trunk/examples/jms/transaction-failover/server1/KILL_ME
   trunk/examples/jms/transaction-failover/server1/client-jndi.properties
   trunk/examples/jms/transaction-failover/server1/hornetq-beans.xml
   trunk/examples/jms/transaction-failover/server1/hornetq-configuration.xml
   trunk/examples/jms/transaction-failover/server1/hornetq-jms.xml
   trunk/examples/jms/transaction-failover/server1/hornetq-users.xml
   trunk/examples/jms/transaction-failover/src/
   trunk/examples/jms/transaction-failover/src/org/
   trunk/examples/jms/transaction-failover/src/org/hornetq/
   trunk/examples/jms/transaction-failover/src/org/hornetq/jms/
   trunk/examples/jms/transaction-failover/src/org/hornetq/jms/example/
   trunk/examples/jms/transaction-failover/src/org/hornetq/jms/example/TransactionFailoverExample.java
Modified:
   trunk/.classpath
   trunk/src/main/org/hornetq/core/client/ClientSession.java
   trunk/src/main/org/hornetq/core/client/impl/ClientConsumerImpl.java
   trunk/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java
   trunk/src/main/org/hornetq/core/client/impl/DelegatingSession.java
   trunk/tests/jms-tests/src/org/hornetq/jms/tests/message/MessageHeaderTest.java
   trunk/tests/src/org/hornetq/tests/integration/cluster/failover/FailoverTest.java
Log:
failover examples

* added examples for JMS failover with and without transactions
* refactored ClientSession to flag its workDone when a consumer effectively consume a message


Modified: trunk/.classpath
===================================================================
--- trunk/.classpath	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/.classpath	2009-10-27 10:18:02 UTC (rev 8146)
@@ -50,6 +50,7 @@
 	<classpathentry kind="src" path="examples/jms/message-group/src"/>
 	<classpathentry kind="src" path="examples/jms/message-priority/src"/>
 	<classpathentry kind="src" path="examples/jms/no-consumer-buffering/src"/>
+	<classpathentry kind="src" path="examples/jms/non-transaction-failover/src"/>
 	<classpathentry kind="src" path="examples/jms/paging/src"/>
 	<classpathentry kind="src" path="examples/jms/perf/src"/>
 	<classpathentry kind="src" path="examples/jms/pre-acknowledge/src"/>
@@ -72,6 +73,7 @@
 	<classpathentry kind="src" path="examples/jms/topic-hierarchies/src"/>
 	<classpathentry kind="src" path="examples/jms/topic-selector-example1/src"/>
 	<classpathentry kind="src" path="examples/jms/topic-selector-example2/src"/>
+	<classpathentry kind="src" path="examples/jms/transaction-failover/src"/>
 	<classpathentry kind="src" path="examples/jms/transactional/src"/>
 	<classpathentry kind="src" path="examples/jms/xa-heuristic/src"/>
 	<classpathentry kind="src" path="examples/jms/xa-receive/src"/>


Property changes on: trunk/examples/jms/non-transaction-failover
___________________________________________________________________
Name: svn:ignore
   + build


Added: trunk/examples/jms/non-transaction-failover/build.bat
===================================================================
--- trunk/examples/jms/non-transaction-failover/build.bat	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/build.bat	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,13 @@
+ at echo off
+
+set "OVERRIDE_ANT_HOME=..\..\..\tools\ant"
+
+if exist "..\..\..\src\bin\build.bat" (
+   rem running from TRUNK
+   call ..\..\..\src\bin\build.bat %*
+) else (
+   rem running from the distro
+   call ..\..\..\bin\build.bat %*
+)
+
+set "OVERRIDE_ANT_HOME="

Added: trunk/examples/jms/non-transaction-failover/build.sh
===================================================================
--- trunk/examples/jms/non-transaction-failover/build.sh	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/build.sh	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+OVERRIDE_ANT_HOME=../../../tools/ant
+export OVERRIDE_ANT_HOME
+
+if [ -f "../../../src/bin/build.sh" ]; then
+   # running from TRUNK
+   ../../../src/bin/build.sh "$@"
+else
+   # running from the distro
+   ../../../bin/build.sh "$@"
+fi
+
+
+


Property changes on: trunk/examples/jms/non-transaction-failover/build.sh
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/jms/non-transaction-failover/build.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/build.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/build.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE project [
+      <!ENTITY libraries SYSTEM "../../../thirdparty/libraries.ent">
+      ]>
+<!--
+  ~ Copyright 2009 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.
+  -->
+
+<project default="run" name="HornetQ JMS Non-transaction Failover Example">
+
+   <import file="../../common/build.xml"/>
+
+   <target name="run" depends="delete-files">
+      <antcall target="runExample">
+         <param name="example.classname" value="org.hornetq.jms.example.NonTransactionFailoverExample"/>
+         <param name="hornetq.example.beans.file" value="server0 server1"/>
+      </antcall>
+   </target>
+
+   <target name="runRemote" depends="delete-files">
+      <antcall target="runExample">
+         <param name="example.classname" value="org.hornetq.jms.example.NonTransactionFailoverExample"/>
+         <param name="hornetq.example.runServer" value="false"/>
+      </antcall>
+   </target>
+     
+   <target name="delete-files" depends="clean">
+      <delete file="./server1/KILL_ME"/>           
+   </target>
+
+</project>

Added: trunk/examples/jms/non-transaction-failover/readme.html
===================================================================
--- trunk/examples/jms/non-transaction-failover/readme.html	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/readme.html	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,166 @@
+<html>
+  <head>
+    <title>HornetQ JMS Failover Without Transactions 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 Failover Without Transactions Example</h1>
+     
+     <p>This example demonstrates two servers coupled as a live-backup pair for high availability (HA), and a client
+     connection failing over from live to backup when the live server is crashed.</p>
+     <p>Failover behavior differs wether the JMS session is transacter or not.</p>
+     <p>When a <em>non-transacted</em> JMS session is used, once and only once delivery is not guaranteed 
+        and it is possible some messages will be lost or delivered twice, depending when the failover to the backup server occurs.</p>
+     <p>It is up to the client to deal with such cases. To ensure once and only once delivery, the client must
+        use transacted JMS sessions (as shown in the example for <a href="../transaction-failover/readme.html">failover with transactions</a>).</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>./build.sh</code> (or <code>build.bat</code> on windows) from this directory</i></p>
+     <p>In this example, the live server is server 1, and the backup server is server 0</p>
+     <p>The connection will initially be created to server1, server 1 will crash, and the client will carry on
+     seamlessly on server 0, the backup server.</p>
+     <br>
+     <ol>
+        <li>Get an initial context for looking up JNDI from server #1.</li>
+        <pre class="prettyprint">
+           initialContext = getContext(1);
+        </pre>
+
+        <li>Look up the JMS resources from JNDI on server #1.</li>
+        <pre class="prettyprint">
+           Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+           ConnectionFactory connectionFactory = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+        </pre>
+
+        <li>Create a JMS Connection</li>
+        <pre class="prettyprint">
+           connection = connectionFactory.createConnection();
+        </pre>
+        
+        <li>Create a JMS <em>non-transacted</em> Session with client acknowledgement</li>
+        <pre class="prettyprint">
+           Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+        </pre>
+        
+        <li>Start the connection to ensure delivery occurs</li>
+        <pre class="prettyprint">
+           connection.start();
+        </pre>
+
+        <li>Create a JMS MessageProducer and MessageConsumer</li>
+        <pre class="prettyprint">
+           MessageProducer producer = session.createProducer(queue);
+           MessageConsumer consumer = session.createConsumer(queue);
+        </pre>
+
+        <li>Send some messages to server #1</li>
+        <pre class="prettyprint">
+           for (int i = 0; i &lt; numMessages; i++)
+           {
+              TextMessage message = session.createTextMessage("This is text message " + i);
+              producer.send(message);
+              System.out.println("Sent message: " + message.getText());
+           }
+        </pre>
+        
+        <li>Receive and acknowledge half of the sent messages</li>
+        <pre class="prettyprint">
+           TextMessage message0 = null;
+           for (int i = 0; i &lt; numMessages / 2; i++)
+           {
+              message0 = (TextMessage)consumer.receive(5000);
+              System.out.println("Got message: " + message0.getText());
+           }
+           message0.acknowledge();
+        </pre>
+        
+        <li>Receive the second half of the sent messages but <em>do not acknowledge them yet</em></li>
+        <pre class="prettyprint">
+           for (int i = numMessages / 2; i &lt; numMessages; i++)
+           {
+              message0 = (TextMessage)consumer.receive(5000);
+              System.out.println("Got message: " + message0.getText());
+           }
+        </pre>
+              
+        <li>Crash server #1, the live server, and wait a little while to make sure it has really crashed.</li>
+        <pre class="prettyprint">
+           killServer(1);
+           Thread.sleep(2000);
+        </pre>
+
+        <li>Acknowledging the second half of the sent messages will fail as failover to the backup server has occured</li>
+        <pre class="prettyprint">
+           try
+           {
+              message0.acknowledge();
+           }
+           catch (JMSException e)
+           {
+              System.out.println("Got exception while acknowledging message: " + e.getMessage());
+              ...
+           }
+        </pre>
+         
+         <li>The client must cope with the failover and recreate the JMS session</li>
+         <pre class="prettyprint">
+            session.close();
+            session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+            producer = session.createProducer(queue);
+            consumer = session.createConsumer(queue);
+         </pre>
+           
+         <li>Consume again the second half of the messages againg. Note that they are not considered as redelivered</li>
+        <pre class="prettyprint">
+           for (int i = numMessages / 2; i &lt; numMessages; i++)
+           {
+              message0 = (TextMessage)consumer.receive(5000);
+              System.out.printf("Got message: %s (redelivered?: %s)\n", message0.getText(), message0.getJMSRedelivered());
+           }
+           message0.acknowledge();
+        </pre>
+        
+        <li>Send some more messages</li>
+        <pre class="prettyprint">
+           for (int i = numMessages; i &lt; numMessages * 2; i++)
+           {
+              TextMessage message = session.createTextMessage("This is text message " + i);
+              producer.send(message);
+              System.out.println("Sent message: " + message.getText());
+           }
+        </pre>
+        
+        <li>Consume them</li>
+        <pre class="prettyprint">
+           for (int i = 0; i &lt; numMessages; i++)
+           {
+              TextMessage message = (TextMessage)consumer.receive(5000);
+              System.out.println("Got message: " + message.getText());
+              message.acknowledge();
+           }
+        </pre>
+
+        <li>And finally, <strong>always</strong> 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">
+           finally
+           {
+              if (connection != null)
+              {
+                 connection.close();
+              }
+
+              if (initialContext != null)
+              {
+                 initialContext.close();
+              }
+           }
+        </pre>
+
+     </ol>
+  </body>
+</html>
\ No newline at end of file


Property changes on: trunk/examples/jms/non-transaction-failover/server0
___________________________________________________________________
Name: svn:ignore
   + data


Added: trunk/examples/jms/non-transaction-failover/server0/client-jndi.properties
===================================================================
--- trunk/examples/jms/non-transaction-failover/server0/client-jndi.properties	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server0/client-jndi.properties	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,3 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://localhost:1099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

Added: trunk/examples/jms/non-transaction-failover/server0/hornetq-beans.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server0/hornetq-beans.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server0/hornetq-beans.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+   <bean name="Naming" class="org.jnp.server.NamingBeanImpl"/>
+
+   <!-- JNDI server. Disable this if you don't want JNDI -->
+   <bean name="JNDIServer" class="org.jnp.server.Main">
+      <property name="namingInfo">
+         <inject bean="Naming"/>
+      </property>
+      <property name="port">1099</property>
+      <property name="bindAddress">localhost</property>
+      <property name="rmiPort">1098</property>
+      <property name="rmiBindAddress">localhost</property>
+   </bean>
+   
+   <!-- MBean server -->
+   <bean name="MBeanServer" class="javax.management.MBeanServer">
+      <constructor factoryClass="java.lang.management.ManagementFactory"
+                   factoryMethod="getPlatformMBeanServer"/>
+   </bean> 
+
+   <!-- The core configuration -->
+   <bean name="Configuration" class="org.hornetq.core.config.impl.FileConfiguration"/>
+
+	<!-- The security manager -->
+   <bean name="HornetQSecurityManager" class="org.hornetq.core.security.impl.HornetQSecurityManagerImpl">
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+
+	<!-- The core server -->
+   <bean name="HornetQServer" class="org.hornetq.core.server.impl.HornetQServerImpl">
+      <constructor>
+         <parameter>
+            <inject bean="Configuration"/>
+         </parameter>
+         <parameter>
+            <inject bean="MBeanServer"/>
+         </parameter>
+         <parameter>
+            <inject bean="HornetQSecurityManager"/>
+         </parameter>        
+      </constructor>
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+   
+   <!-- The JMS server -->
+   <bean name="JMSServerManager" class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
+      <constructor>         
+         <parameter>
+            <inject bean="HornetQServer"/>
+         </parameter>         
+      </constructor>
+   </bean>
+
+</deployment>

Added: trunk/examples/jms/non-transaction-failover/server0/hornetq-configuration.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server0/hornetq-configuration.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server0/hornetq-configuration.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,37 @@
+<configuration xmlns="urn:hornetq"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd">
+   <backup>true</backup>
+   
+   <!-- Connectors -->
+
+   <connectors>
+      <connector name="netty-connector">
+         <factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5445" type="Integer"/>
+      </connector>
+   </connectors>      
+
+   <!-- Acceptors -->
+   <acceptors>
+      <acceptor name="netty-acceptor">
+         <factory-class>org.hornetq.integration.transports.netty.NettyAcceptorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5445" type="Integer"/>
+      </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="createTempQueue" roles="guest"/>
+         <permission type="deleteTempQueue" roles="guest"/>
+         <permission type="consume" roles="guest"/>
+         <permission type="send" roles="guest"/>
+      </security-setting>
+   </security-settings>
+
+</configuration>

Added: trunk/examples/jms/non-transaction-failover/server0/hornetq-jms.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server0/hornetq-jms.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server0/hornetq-jms.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,18 @@
+<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">
+      <connector-ref connector-name="netty-connector"/>
+
+      <entries>
+         <entry name="ConnectionFactory"/>
+      </entries>
+   </connection-factory>
+
+   <!--the queue used by the example-->
+   <queue name="exampleQueue">
+      <entry name="/queue/exampleQueue"/>
+   </queue>
+
+</configuration>

Added: trunk/examples/jms/non-transaction-failover/server0/hornetq-users.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server0/hornetq-users.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server0/hornetq-users.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -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


Property changes on: trunk/examples/jms/non-transaction-failover/server1
___________________________________________________________________
Name: svn:ignore
   + data


Added: trunk/examples/jms/non-transaction-failover/server1/KILL_ME
===================================================================

Added: trunk/examples/jms/non-transaction-failover/server1/client-jndi.properties
===================================================================
--- trunk/examples/jms/non-transaction-failover/server1/client-jndi.properties	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server1/client-jndi.properties	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,3 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://localhost:2099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

Added: trunk/examples/jms/non-transaction-failover/server1/hornetq-beans.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server1/hornetq-beans.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server1/hornetq-beans.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+   <bean name="Naming" class="org.jnp.server.NamingBeanImpl"/>
+
+   <!-- JNDI server. Disable this if you don't want JNDI -->
+   <bean name="JNDIServer" class="org.jnp.server.Main">
+      <property name="namingInfo">
+         <inject bean="Naming"/>
+      </property>
+      <property name="port">2099</property>
+      <property name="bindAddress">localhost</property>
+      <property name="rmiPort">2098</property>
+      <property name="rmiBindAddress">localhost</property>
+   </bean>
+   
+   <!-- MBean server -->
+   <bean name="MBeanServer" class="javax.management.MBeanServer">
+      <constructor factoryClass="java.lang.management.ManagementFactory"
+                   factoryMethod="getPlatformMBeanServer"/>
+   </bean> 
+
+   <!-- The core configuration -->
+   <bean name="Configuration" class="org.hornetq.core.config.impl.FileConfiguration"/>
+
+	<!-- The security manager -->
+   <bean name="HornetQSecurityManager" class="org.hornetq.core.security.impl.HornetQSecurityManagerImpl">
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+
+	<!-- The core server -->
+   <bean name="HornetQServer" class="org.hornetq.core.server.impl.HornetQServerImpl">
+      <constructor>
+         <parameter>
+            <inject bean="Configuration"/>
+         </parameter>
+         <parameter>
+            <inject bean="MBeanServer"/>
+         </parameter>
+         <parameter>
+            <inject bean="HornetQSecurityManager"/>
+         </parameter>        
+      </constructor>
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+   
+   <!-- The JMS server -->
+   <bean name="JMSServerManager" class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
+      <constructor>         
+         <parameter>
+            <inject bean="HornetQServer"/>
+         </parameter>         
+      </constructor>
+   </bean>
+
+</deployment>

Added: trunk/examples/jms/non-transaction-failover/server1/hornetq-configuration.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server1/hornetq-configuration.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server1/hornetq-configuration.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,42 @@
+<configuration xmlns="urn:hornetq"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="urn:hornetq ../../../src/schema/hornetq-configuration.xsd">
+   <backup-connector-ref connector-name="backup-connector"/>
+   
+   <!-- Connectors -->
+
+   <connectors>
+      <connector name="netty-connector">
+         <factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5446" type="Integer"/>
+      </connector>
+   
+      <connector name="backup-connector">
+        <factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
+        <param key="hornetq.remoting.netty.port" value="5445" type="Integer"/>
+      </connector>
+   </connectors>
+   
+   <!-- Acceptors -->
+   <acceptors>
+      <acceptor name="netty-acceptor">
+         <factory-class>org.hornetq.integration.transports.netty.NettyAcceptorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5446" type="Integer"/>
+      </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="createTempQueue" roles="guest"/>
+         <permission type="deleteTempQueue" roles="guest"/>
+         <permission type="consume" roles="guest"/>
+         <permission type="send" roles="guest"/>
+      </security-setting>
+   </security-settings>
+   
+</configuration>

Added: trunk/examples/jms/non-transaction-failover/server1/hornetq-jms.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server1/hornetq-jms.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server1/hornetq-jms.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,18 @@
+<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">
+      <connector-ref connector-name="netty-connector" backup-connector-name="backup-connector"/>
+
+      <entries>
+         <entry name="ConnectionFactory"/>
+      </entries>
+   </connection-factory>
+
+   <!--the queue used by the example-->
+   <queue name="exampleQueue">
+      <entry name="/queue/exampleQueue"/>
+   </queue>
+
+</configuration>

Added: trunk/examples/jms/non-transaction-failover/server1/hornetq-users.xml
===================================================================
--- trunk/examples/jms/non-transaction-failover/server1/hornetq-users.xml	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/server1/hornetq-users.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -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

Added: trunk/examples/jms/non-transaction-failover/src/org/hornetq/jms/example/NonTransactionFailoverExample.java
===================================================================
--- trunk/examples/jms/non-transaction-failover/src/org/hornetq/jms/example/NonTransactionFailoverExample.java	                        (rev 0)
+++ trunk/examples/jms/non-transaction-failover/src/org/hornetq/jms/example/NonTransactionFailoverExample.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2009 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.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 failover of the JMS connection from one node to another
+ * when the live server crashes using a JMS <em>non-transacted</em> session.
+ *
+ * @author <a href="mailto:jmesnil at redhat.com">Jeff Mesnil</a>
+ */
+public class NonTransactionFailoverExample extends HornetQExample
+{
+   public static void main(String[] args)
+   {
+      new NonTransactionFailoverExample().run(args);
+   }
+
+   public boolean runExample() throws Exception
+   {
+      final int numMessages = 10;
+
+      Connection connection = null;
+
+      InitialContext initialContext = null;
+
+      try
+      {
+         // Step 1. Get an initial context for looking up JNDI from the server #1
+         initialContext = getContext(1);
+
+         // Step 2. Look up the JMS resources from JNDI
+         Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+         ConnectionFactory connectionFactory = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+         // Step 3. Create a JMS Connection
+         connection = connectionFactory.createConnection();
+
+         // Step 4. Create a *non-transacted* JMS Session with client acknwoledgement
+         Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+
+         // Step 5. Start the connection to ensure delivery occurs
+         connection.start();
+
+         // Step 6. Create a JMS MessageProducer and a MessageConsumer
+         MessageProducer producer = session.createProducer(queue);
+         MessageConsumer consumer = session.createConsumer(queue);
+
+         // Step 7. Send some messages to server #1, the live server
+         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 8. Receive and acknowledge half of the sent messages
+         TextMessage message0 = null;
+         for (int i = 0; i < numMessages / 2; i++)
+         {
+            message0 = (TextMessage)consumer.receive(5000);
+            System.out.println("Got message: " + message0.getText());
+         }
+         message0.acknowledge();
+
+         // Step 9. Receive the 2nd half of the sent messages but *do not* acknowledge them yet
+         for (int i = numMessages / 2; i < numMessages; i++)
+         {
+            message0 = (TextMessage)consumer.receive(5000);
+            System.out.println("Got message: " + message0.getText());
+         }
+
+         // Step 10. Crash server #1, the live server, and wait a little while to make sure
+         // it has really crashed
+         killServer(1);
+         Thread.sleep(2000);
+
+         // Step 11. Acknowledging the 2nd half of the sent messages will fail as failover to the
+         // backup server has occured
+         try
+         {
+            message0.acknowledge();
+         }
+         catch (JMSException e)
+         {
+            System.out.println("Got exception while acknowledging message: " + e.getMessage());
+            // Step 12. Close the JMS session and recreate the JMS objects
+            session.close();
+            session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
+            producer = session.createProducer(queue);
+            consumer = session.createConsumer(queue);
+         }
+
+         // Step 13. Consume again the 2nd half of the messages again. Note that they are not considered as redelivered.
+         for (int i = numMessages / 2; i < numMessages; i++)
+         {
+            message0 = (TextMessage)consumer.receive(5000);
+            System.out.printf("Got message: %s (redelivered?: %s)\n", message0.getText(), message0.getJMSRedelivered());
+         }
+         message0.acknowledge();
+
+         // Step 14. 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 15. Consume them
+         for (int i = 0; i < numMessages; i++)
+         {
+            TextMessage message = (TextMessage)consumer.receive(5000);
+            System.out.println("Got message: " + message.getText());
+            message.acknowledge();
+         }
+
+         return true;
+      }
+      finally
+      {
+         // Step 16. Be sure to close our resources!
+
+         if (connection != null)
+         {
+            connection.close();
+         }
+
+         if (initialContext != null)
+         {
+            initialContext.close();
+         }
+      }
+   }
+
+}


Property changes on: trunk/examples/jms/transaction-failover
___________________________________________________________________
Name: svn:ignore
   + build


Added: trunk/examples/jms/transaction-failover/build.bat
===================================================================
--- trunk/examples/jms/transaction-failover/build.bat	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/build.bat	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,13 @@
+ at echo off
+
+set "OVERRIDE_ANT_HOME=..\..\..\tools\ant"
+
+if exist "..\..\..\src\bin\build.bat" (
+   rem running from TRUNK
+   call ..\..\..\src\bin\build.bat %*
+) else (
+   rem running from the distro
+   call ..\..\..\bin\build.bat %*
+)
+
+set "OVERRIDE_ANT_HOME="

Added: trunk/examples/jms/transaction-failover/build.sh
===================================================================
--- trunk/examples/jms/transaction-failover/build.sh	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/build.sh	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+OVERRIDE_ANT_HOME=../../../tools/ant
+export OVERRIDE_ANT_HOME
+
+if [ -f "../../../src/bin/build.sh" ]; then
+   # running from TRUNK
+   ../../../src/bin/build.sh "$@"
+else
+   # running from the distro
+   ../../../bin/build.sh "$@"
+fi
+
+
+


Property changes on: trunk/examples/jms/transaction-failover/build.sh
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/examples/jms/transaction-failover/build.xml
===================================================================
--- trunk/examples/jms/transaction-failover/build.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/build.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE project [
+      <!ENTITY libraries SYSTEM "../../../thirdparty/libraries.ent">
+      ]>
+<!--
+  ~ Copyright 2009 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.
+  -->
+
+<project default="run" name="HornetQ JMS Transaction Failover Example">
+
+   <import file="../../common/build.xml"/>
+
+   <target name="run" depends="delete-files">
+      <antcall target="runExample">
+         <param name="example.classname" value="org.hornetq.jms.example.TransactionFailoverExample"/>
+         <param name="hornetq.example.beans.file" value="server0 server1"/>
+      </antcall>
+   </target>
+
+   <target name="runRemote" depends="delete-files">
+      <antcall target="runExample">
+         <param name="example.classname" value="org.hornetq.jms.example.TransactionFailoverExample"/>
+         <param name="hornetq.example.runServer" value="false"/>
+      </antcall>
+   </target>
+     
+   <target name="delete-files" depends="clean">
+      <delete file="./server1/KILL_ME"/>           
+   </target>
+
+</project>

Added: trunk/examples/jms/transaction-failover/readme.html
===================================================================
--- trunk/examples/jms/transaction-failover/readme.html	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/readme.html	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,139 @@
+<html>
+  <head>
+    <title>HornetQ JMS Failover With Transaction 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 Failover With Transaction Example</h1>
+     
+     <p>This example demonstrates two servers coupled as a live-backup pair for high availability (HA), and a client
+     connection failing over from live to backup when the live server is crashed.</p>
+     <p>Failover behavior differs wether the JMS session is transacter or not.</p>
+     <p>When a <em>transacted</em> JMS session is used, once-and-only once delivery is guaranteed.</p>
+     <ul>
+        <li>if the failover occurs while there is an in-flight transaction, the transaction will be flagged as <em>rollback only</em> and the JMS client will need to retry the transaction work.</li>
+        <li>if the failover occurs while there is <em>no</em> in-flight transaction, the failover will be transparent to the user.</li>
+     </ul>
+     <p>HornetQ also provides an example for <a href="../non-transactional-failover/readme.html">non-transaction failover</a>.</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>./build.sh</code> (or <code>build.bat</code> on windows) from this directory</i></p>
+     <p>In this example, the live server is server 1, and the backup server is server 0</p>
+     <p>The connection will initially be created to server1, server 1 will crash, and the client will carry on
+     seamlessly on server 0, the backup server.</p>
+     <br>
+     <ol>
+        <li>Get an initial context for looking up JNDI from server #1.</li>
+        <pre class="prettyprint">
+           initialContext = getContext(1);
+        </pre>
+
+        <li>Look up the JMS resources from JNDI on server #1.</li>
+        <pre class="prettyprint">
+           Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+           ConnectionFactory connectionFactory = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+        </pre>
+
+        <li>Create a JMS Connection</li>
+        <pre class="prettyprint">
+           connection = connectionFactory.createConnection();
+        </pre>
+        
+        <li>Create a JMS <em>transacted</em> Session</li>
+        <pre class="prettyprint">
+           Session session = connection.createSession(true, 0);
+        </pre>
+        
+        <li>Start the connection to ensure delivery occurs</li>
+        <pre class="prettyprint">
+           connection.start();
+        </pre>
+
+        <li>Create a JMS MessageProducer</li>
+        <pre class="prettyprint">
+           MessageProducer producer = session.createProducer(queue);
+        </pre>
+
+        <li>Create a JMS MessageConsumer</li>
+        <pre class="prettyprint">
+           MessageConsumer consumer = session.createConsumer(queue);
+        </pre>
+
+        <li>Send some messages to server #1 and commit the session</li>
+        <pre class="prettyprint">
+           for (int i = 0; i &lt; numMessages; i++)
+           {
+              TextMessage message = session.createTextMessage("This is text message " + i);
+              producer.send(message);
+              System.out.println("Sent message: " + message.getText());
+           }
+           session.commit();
+        </pre>
+        
+        <li>Crash server #1, the live server, and wait a little while to make sure
+            it has really crashed.<br />
+            When server #1 crashes, the client automatically detects the failure and automatically
+            fails over from server #1 to server #0 (in your real program you wouldn't need to sleep).
+        </li>
+        <pre class="prettyprint">
+           killServer(1); // This causes the live server to crash
+           Thread.sleep(2000); // Just wait a little while to make sure the live server has really crashed.
+        </pre> 
+        
+        <li>The client is transparently reconnected to server #0 - the backup server.
+           As no work has been done by the session during the failover, we can <em>transparently</em> consume messages
+           from the session.</li>
+        <pre class="prettyprint">
+           for (int i = 0; i &lt; numMessages; i++)
+           {
+              TextMessage message0 = (TextMessage)consumer.receive(5000);
+              System.out.println("Got message: " + message0.getText());
+           }         
+           session.commit();
+        </pre>
+        
+        <li>Send some more messages and commit the session</li>
+        <pre class="prettyprint">
+           for (int i = numMessages; i &lt; numMessages * 2; i++)
+           {
+              TextMessage message = session.createTextMessage("This is text message " + i);
+              producer.send(message);
+              System.out.println("Sent message: " + message.getText());
+           }
+           session.commit();
+        </pre>
+        
+        <li>Consume them</li>
+        <pre class="prettyprint">
+           for (int i = 0; i &lt; numMessages; i++)
+           {
+              TextMessage message0 = (TextMessage)consumer.receive(5000);
+              System.out.println("Got message: " + message0.getText());
+           }
+           session.commit();
+        </pre>
+
+        <li>And finally, <strong>always</strong> 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">
+           finally
+           {
+              if (connection != null)
+              {
+                 connection.close();
+              }
+
+              if (initialContext != null)
+              {
+                 initialContext.close();
+              }
+           }
+        </pre>
+
+     </ol>
+  </body>
+</html>
\ No newline at end of file


Property changes on: trunk/examples/jms/transaction-failover/server0
___________________________________________________________________
Name: svn:ignore
   + data


Added: trunk/examples/jms/transaction-failover/server0/client-jndi.properties
===================================================================
--- trunk/examples/jms/transaction-failover/server0/client-jndi.properties	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server0/client-jndi.properties	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,3 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://localhost:1099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

Added: trunk/examples/jms/transaction-failover/server0/hornetq-beans.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server0/hornetq-beans.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server0/hornetq-beans.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+   <bean name="Naming" class="org.jnp.server.NamingBeanImpl"/>
+
+   <!-- JNDI server. Disable this if you don't want JNDI -->
+   <bean name="JNDIServer" class="org.jnp.server.Main">
+      <property name="namingInfo">
+         <inject bean="Naming"/>
+      </property>
+      <property name="port">1099</property>
+      <property name="bindAddress">localhost</property>
+      <property name="rmiPort">1098</property>
+      <property name="rmiBindAddress">localhost</property>
+   </bean>
+   
+   <!-- MBean server -->
+   <bean name="MBeanServer" class="javax.management.MBeanServer">
+      <constructor factoryClass="java.lang.management.ManagementFactory"
+                   factoryMethod="getPlatformMBeanServer"/>
+   </bean> 
+
+   <!-- The core configuration -->
+   <bean name="Configuration" class="org.hornetq.core.config.impl.FileConfiguration"/>
+
+	<!-- The security manager -->
+   <bean name="HornetQSecurityManager" class="org.hornetq.core.security.impl.HornetQSecurityManagerImpl">
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+
+	<!-- The core server -->
+   <bean name="HornetQServer" class="org.hornetq.core.server.impl.HornetQServerImpl">
+      <constructor>
+         <parameter>
+            <inject bean="Configuration"/>
+         </parameter>
+         <parameter>
+            <inject bean="MBeanServer"/>
+         </parameter>
+         <parameter>
+            <inject bean="HornetQSecurityManager"/>
+         </parameter>        
+      </constructor>
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+   
+   <!-- The JMS server -->
+   <bean name="JMSServerManager" class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
+      <constructor>         
+         <parameter>
+            <inject bean="HornetQServer"/>
+         </parameter>         
+      </constructor>
+   </bean>
+
+</deployment>

Added: trunk/examples/jms/transaction-failover/server0/hornetq-configuration.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server0/hornetq-configuration.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server0/hornetq-configuration.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,37 @@
+<configuration xmlns="urn:hornetq"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="urn:hornetq /schema/hornetq-configuration.xsd">
+   <backup>true</backup>
+   
+   <!-- Connectors -->
+
+   <connectors>
+      <connector name="netty-connector">
+         <factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5445" type="Integer"/>
+      </connector>
+   </connectors>      
+
+   <!-- Acceptors -->
+   <acceptors>
+      <acceptor name="netty-acceptor">
+         <factory-class>org.hornetq.integration.transports.netty.NettyAcceptorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5445" type="Integer"/>
+      </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="createTempQueue" roles="guest"/>
+         <permission type="deleteTempQueue" roles="guest"/>
+         <permission type="consume" roles="guest"/>
+         <permission type="send" roles="guest"/>
+      </security-setting>
+   </security-settings>
+
+</configuration>

Added: trunk/examples/jms/transaction-failover/server0/hornetq-jms.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server0/hornetq-jms.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server0/hornetq-jms.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,18 @@
+<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">
+      <connector-ref connector-name="netty-connector"/>
+
+      <entries>
+         <entry name="ConnectionFactory"/>
+      </entries>
+   </connection-factory>
+
+   <!--the queue used by the example-->
+   <queue name="exampleQueue">
+      <entry name="/queue/exampleQueue"/>
+   </queue>
+
+</configuration>

Added: trunk/examples/jms/transaction-failover/server0/hornetq-users.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server0/hornetq-users.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server0/hornetq-users.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -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


Property changes on: trunk/examples/jms/transaction-failover/server1
___________________________________________________________________
Name: svn:ignore
   + data


Added: trunk/examples/jms/transaction-failover/server1/KILL_ME
===================================================================

Added: trunk/examples/jms/transaction-failover/server1/client-jndi.properties
===================================================================
--- trunk/examples/jms/transaction-failover/server1/client-jndi.properties	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server1/client-jndi.properties	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,3 @@
+java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
+java.naming.provider.url=jnp://localhost:2099
+java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces

Added: trunk/examples/jms/transaction-failover/server1/hornetq-beans.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server1/hornetq-beans.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server1/hornetq-beans.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<deployment xmlns="urn:jboss:bean-deployer:2.0">
+
+   <bean name="Naming" class="org.jnp.server.NamingBeanImpl"/>
+
+   <!-- JNDI server. Disable this if you don't want JNDI -->
+   <bean name="JNDIServer" class="org.jnp.server.Main">
+      <property name="namingInfo">
+         <inject bean="Naming"/>
+      </property>
+      <property name="port">2099</property>
+      <property name="bindAddress">localhost</property>
+      <property name="rmiPort">2098</property>
+      <property name="rmiBindAddress">localhost</property>
+   </bean>
+   
+   <!-- MBean server -->
+   <bean name="MBeanServer" class="javax.management.MBeanServer">
+      <constructor factoryClass="java.lang.management.ManagementFactory"
+                   factoryMethod="getPlatformMBeanServer"/>
+   </bean> 
+
+   <!-- The core configuration -->
+   <bean name="Configuration" class="org.hornetq.core.config.impl.FileConfiguration"/>
+
+	<!-- The security manager -->
+   <bean name="HornetQSecurityManager" class="org.hornetq.core.security.impl.HornetQSecurityManagerImpl">
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+
+	<!-- The core server -->
+   <bean name="HornetQServer" class="org.hornetq.core.server.impl.HornetQServerImpl">
+      <constructor>
+         <parameter>
+            <inject bean="Configuration"/>
+         </parameter>
+         <parameter>
+            <inject bean="MBeanServer"/>
+         </parameter>
+         <parameter>
+            <inject bean="HornetQSecurityManager"/>
+         </parameter>        
+      </constructor>
+      <start ignored="true"/>
+      <stop ignored="true"/>
+   </bean>
+   
+   <!-- The JMS server -->
+   <bean name="JMSServerManager" class="org.hornetq.jms.server.impl.JMSServerManagerImpl">
+      <constructor>         
+         <parameter>
+            <inject bean="HornetQServer"/>
+         </parameter>         
+      </constructor>
+   </bean>
+
+</deployment>

Added: trunk/examples/jms/transaction-failover/server1/hornetq-configuration.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server1/hornetq-configuration.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server1/hornetq-configuration.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,42 @@
+<configuration xmlns="urn:hornetq"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="urn:hornetq ../../../src/schema/hornetq-configuration.xsd">
+   <backup-connector-ref connector-name="backup-connector"/>
+   
+   <!-- Connectors -->
+
+   <connectors>
+      <connector name="netty-connector">
+         <factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5446" type="Integer"/>
+      </connector>
+   
+      <connector name="backup-connector">
+        <factory-class>org.hornetq.integration.transports.netty.NettyConnectorFactory</factory-class>
+        <param key="hornetq.remoting.netty.port" value="5445" type="Integer"/>
+      </connector>
+   </connectors>
+   
+   <!-- Acceptors -->
+   <acceptors>
+      <acceptor name="netty-acceptor">
+         <factory-class>org.hornetq.integration.transports.netty.NettyAcceptorFactory</factory-class>
+         <param key="hornetq.remoting.netty.port" value="5446" type="Integer"/>
+      </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="createTempQueue" roles="guest"/>
+         <permission type="deleteTempQueue" roles="guest"/>
+         <permission type="consume" roles="guest"/>
+         <permission type="send" roles="guest"/>
+      </security-setting>
+   </security-settings>
+   
+</configuration>

Added: trunk/examples/jms/transaction-failover/server1/hornetq-jms.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server1/hornetq-jms.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server1/hornetq-jms.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,18 @@
+<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">
+      <connector-ref connector-name="netty-connector" backup-connector-name="backup-connector"/>
+
+      <entries>
+         <entry name="ConnectionFactory"/>
+      </entries>
+   </connection-factory>
+
+   <!--the queue used by the example-->
+   <queue name="exampleQueue">
+      <entry name="/queue/exampleQueue"/>
+   </queue>
+
+</configuration>

Added: trunk/examples/jms/transaction-failover/server1/hornetq-users.xml
===================================================================
--- trunk/examples/jms/transaction-failover/server1/hornetq-users.xml	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/server1/hornetq-users.xml	2009-10-27 10:18:02 UTC (rev 8146)
@@ -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

Added: trunk/examples/jms/transaction-failover/src/org/hornetq/jms/example/TransactionFailoverExample.java
===================================================================
--- trunk/examples/jms/transaction-failover/src/org/hornetq/jms/example/TransactionFailoverExample.java	                        (rev 0)
+++ trunk/examples/jms/transaction-failover/src/org/hornetq/jms/example/TransactionFailoverExample.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2009 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.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 failover of the JMS connection from one node to another
+ * when the live server crashes using a JMS <em>transacted</em> session.
+ *
+ * @author <a href="mailto:jmesnil at redhat.com">Jeff Mesnil</a>
+ */
+public class TransactionFailoverExample extends HornetQExample
+{
+   public static void main(String[] args)
+   {
+      new TransactionFailoverExample().run(args);
+   }
+
+   public boolean runExample() throws Exception
+   {
+      final int numMessages = 10;
+
+      Connection connection = null;
+
+      InitialContext initialContext = null;
+
+      try
+      {
+         // Step 1. Get an initial context for looking up JNDI from the server #1
+         initialContext = getContext(1);
+
+         // Step 2. Look-up the JMS resources from JNDI
+         Queue queue = (Queue)initialContext.lookup("/queue/exampleQueue");
+         ConnectionFactory connectionFactory = (ConnectionFactory)initialContext.lookup("/ConnectionFactory");
+
+         // Step 3. We create a JMS Connection
+         connection = connectionFactory.createConnection();
+
+         // Step 4. We create a *transacted* JMS Session
+         Session session = connection.createSession(true, 0);
+         
+         // Step 5. We start the connection to ensure delivery occurs
+         connection.start();
+
+         // Step 6. We create a JMS MessageProducer
+         MessageProducer producer = session.createProducer(queue);
+
+         // Step 7. We create a JMS MessageConsumer
+         MessageConsumer consumer = session.createConsumer(queue);
+
+         // Step 8. We send some messages to server #1, the live server
+         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());
+         }      
+         session.commit();
+
+         // Step 9. We now cause server #1, the live server to crash, and wait a little while to make sure
+         // it has really crashed
+         killServer(1);
+         Thread.sleep(2000);
+
+         // Step 10. We are now transparently reconnected to server #0, the backup server.
+         // We consume the messages sent before the crash of the live server and commit the session.
+         for (int i = 0; i < numMessages; i++)
+         {
+            TextMessage message0 = (TextMessage)consumer.receive(5000);
+            System.out.println("Got message: " + message0.getText());
+         }    
+         session.commit();
+
+         // Step 11. We now send some more messages and commit the session
+         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());
+         }
+         session.commit();
+
+         // Step 12. And consume them and commit the session
+         for (int i = 0; i < numMessages; i++)
+         {
+            TextMessage message0 = (TextMessage)consumer.receive(5000);
+            System.out.println("Got message: " + message0.getText());
+         }
+         session.commit();
+
+         return true;
+      }
+      finally
+      {
+         // Step 13. Be sure to close our resources!
+
+         if (connection != null)
+         {
+            System.out.println("CLOSING");
+            connection.close();
+            System.out.println("CLOSED");
+         }
+
+         if (initialContext != null)
+         {
+            initialContext.close();
+         }
+      }
+   }
+
+}

Modified: trunk/src/main/org/hornetq/core/client/ClientSession.java
===================================================================
--- trunk/src/main/org/hornetq/core/client/ClientSession.java	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/src/main/org/hornetq/core/client/ClientSession.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -117,6 +117,8 @@
 
    XAResource getXAResource();
 
+   boolean isRollbackOnly();
+
    void commit() throws HornetQException;
 
    void rollback() throws HornetQException;

Modified: trunk/src/main/org/hornetq/core/client/impl/ClientConsumerImpl.java
===================================================================
--- trunk/src/main/org/hornetq/core/client/impl/ClientConsumerImpl.java	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/src/main/org/hornetq/core/client/impl/ClientConsumerImpl.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -245,6 +245,8 @@
 
             if (m != null)
             {
+               session.workDone();
+               
                if (m.containsProperty(FORCED_DELIVERY_MESSAGE))
                {
                   Long seq = (Long)m.getProperty(FORCED_DELIVERY_MESSAGE);
@@ -707,6 +709,9 @@
       {
          return;
       }
+
+      session.workDone();
+      
       // We pull the message from the buffer from inside the Runnable so we can ensure priority
       // ordering. If we just added a Runnable with the message to the executor immediately as we get it
       // we could not do that

Modified: trunk/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java
===================================================================
--- trunk/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/src/main/org/hornetq/core/client/impl/ClientSessionImpl.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -475,6 +475,11 @@
       workDone = false;
    }
 
+   public boolean isRollbackOnly()
+   {
+      return rollbackOnly;
+   }
+   
    public void rollback() throws HornetQException
    {
       rollback(false);
@@ -511,6 +516,8 @@
       {
          start();
       }
+      
+      rollbackOnly = false;
    }
 
    public ClientMessage createClientMessage(final byte type,
@@ -712,8 +719,6 @@
 
          clMessage.setFlowControlSize(message.getRequiredBufferSize());
 
-         workDone();
-
          consumer.handleMessage(message.getClientMessage());
       }
    }

Modified: trunk/src/main/org/hornetq/core/client/impl/DelegatingSession.java
===================================================================
--- trunk/src/main/org/hornetq/core/client/impl/DelegatingSession.java	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/src/main/org/hornetq/core/client/impl/DelegatingSession.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -462,6 +462,11 @@
    {
       session.rollback();
    }
+   
+   public boolean isRollbackOnly()
+   {
+      return session.isRollbackOnly();
+   }
 
    public void rollback(boolean considerLastMessageAsDelivered) throws HornetQException
    {

Modified: trunk/tests/jms-tests/src/org/hornetq/jms/tests/message/MessageHeaderTest.java
===================================================================
--- trunk/tests/jms-tests/src/org/hornetq/jms/tests/message/MessageHeaderTest.java	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/tests/jms-tests/src/org/hornetq/jms/tests/message/MessageHeaderTest.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -1028,6 +1028,12 @@
       {
       }
 
+      public boolean isRollbackOnly()
+      {
+
+         return false;
+      }
+
       public void rollback() throws HornetQException
       {
       }

Modified: trunk/tests/src/org/hornetq/tests/integration/cluster/failover/FailoverTest.java
===================================================================
--- trunk/tests/src/org/hornetq/tests/integration/cluster/failover/FailoverTest.java	2009-10-27 02:24:40 UTC (rev 8145)
+++ trunk/tests/src/org/hornetq/tests/integration/cluster/failover/FailoverTest.java	2009-10-27 10:18:02 UTC (rev 8146)
@@ -222,6 +222,8 @@
       
       fail(session, latch);
 
+      assertTrue(session.isRollbackOnly());
+
       try
       {
          session.commit();
@@ -271,10 +273,92 @@
 
       session.addFailureListener(new MyListener());
 
+      ClientProducer producer = session.createProducer(ADDRESS);
+
+      final int numMessages = 100;
+
+      for (int i = 0; i < numMessages; i++)
+      {
+         ClientMessage message = session.createClientMessage(i % 2 == 0);
+
+         setBody(i, message);
+
+         message.putIntProperty("counter", i);
+
+         producer.send(message);
+      }
+
+      session.commit();
+
+      fail(session, latch);
+
+      // committing again should work since didn't send anything since last commit
+
+      assertFalse(session.isRollbackOnly());
+
+      session.commit();
+
       ClientConsumer consumer = session.createConsumer(ADDRESS);
 
       session.start();
 
+      for (int i = 0; i < numMessages; i++)
+      {
+         // Only the persistent messages will survive
+
+         if (i % 2 == 0)
+         {
+            ClientMessage message = consumer.receive(1000);
+
+            assertNotNull(message);
+
+            assertMessageBody(i, message);
+
+            assertEquals(i, message.getProperty("counter"));
+
+            message.acknowledge();
+         }
+      }
+
+      assertNull(consumer.receive(1000));
+      
+      session.commit();
+
+      session.close();
+
+      assertEquals(0, sf.numSessions());
+
+      assertEquals(0, sf.numConnections());
+   }
+
+   public void testTransactedMessagesWithConsumerStartedBedoreFailover() throws Exception
+   {
+      ClientSessionFactoryInternal sf = getSessionFactory();
+
+      sf.setBlockOnNonPersistentSend(true);
+      sf.setBlockOnPersistentSend(true);
+
+      ClientSession session = sf.createSession(false, false);
+
+      session.createQueue(ADDRESS, ADDRESS, null, true);
+
+      final CountDownLatch latch = new CountDownLatch(1);
+
+      class MyListener implements FailureListener
+      {
+         public void connectionFailed(HornetQException me)
+         {
+            latch.countDown();
+         }
+      }
+
+      session.addFailureListener(new MyListener());
+
+      // create a consumer and start the session before failover
+      ClientConsumer consumer = session.createConsumer(ADDRESS);
+
+      session.start();
+
       ClientProducer producer = session.createProducer(ADDRESS);
 
       final int numMessages = 100;
@@ -290,15 +374,23 @@
          producer.send(message);
       }
 
+      // messages will be delivered to the consumer when the session is committed
       session.commit();
 
+      assertFalse(session.isRollbackOnly());
+
       fail(session, latch);
 
-      // committing again should work since didn't send anything since last commit
-
       session.commit();
+      
+      session.close();
+      
+      session = sf.createSession(false, false);
+      
+      consumer = session.createConsumer(ADDRESS);
 
-
+      session.start();
+      
       for (int i = 0; i < numMessages; i++)
       {
          // Only the persistent messages will survive
@@ -327,7 +419,7 @@
 
       assertEquals(0, sf.numConnections());
    }
-
+   
    public void testTransactedMessagesConsumedSoRollback() throws Exception
    {
       ClientSessionFactoryInternal sf = getSessionFactory();
@@ -389,6 +481,8 @@
 
       fail(session2, latch);
 
+      assertTrue(session2.isRollbackOnly());
+      
       try
       {
          session2.commit();
@@ -474,6 +568,8 @@
 
       fail(session2, latch);
 
+      assertFalse(session2.isRollbackOnly());
+      
       consumer = session2.createConsumer(ADDRESS);
 
       for (int i = numMessages / 2; i < numMessages; i++)
@@ -1637,7 +1733,8 @@
 
                   try
                   {
-                     session.commit();                     
+                     session.commit();
+                     fail("commit succeeded");
                   }
                   catch (HornetQException e2)
                   {



More information about the hornetq-commits mailing list